Version Description
- May 4th, 2015 =
- Added new filter to allow for custom images to be used in place of font awesome icons (Props Pete Nelson)
- Added
Download this release
Release Info
Developer | eherman24 |
Plugin | Timeline Express |
Version | 1.1.6.7 |
Comparing to | |
See all releases |
Code changes from version 1.1.6.6 to 1.1.6.7
- README.md +432 -0
- classes/class.timeline-express.php +18 -10
- css/timeline-express-css3-slideshow.css +142 -142
- css/timeline-express-single-page.css +4 -4
- languages/timeline-express-it_IT.mo +0 -0
- languages/timeline-express-it_IT.po +839 -0
- languages/timeline-express.pot +796 -0
- lib/about-metabox-template.php +4 -4
- lib/cmb_metaboxes/helpers/cmb_Meta_Box_Sanitize.php +346 -346
- lib/cmb_metaboxes/helpers/cmb_Meta_Box_Show_Filters.php +105 -105
- lib/cmb_metaboxes/helpers/cmb_Meta_Box_ajax.php +203 -203
- lib/cmb_metaboxes/helpers/cmb_Meta_Box_field.php +497 -497
- lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php +794 -794
- lib/cmb_metaboxes/init.php +1185 -1185
- lib/cmb_metaboxes/js/cmb.js +797 -797
- lib/cmb_metaboxes/js/jquery.datePicker.min.js +2038 -2038
- lib/cmb_metaboxes/js/jquery.timePicker.min.js +12 -12
- lib/cmb_metaboxes/readme.md +296 -296
- lib/cmb_metaboxes/style.css +621 -621
- lib/support-contact-form.php +48 -48
- pages/support.php +207 -207
- pages/welcome.php +5 -5
- readme.txt +14 -2
- timeline-express.php +2 -2
README.md
ADDED
@@ -0,0 +1,432 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Timeline Express v1.1.6.7
|
2 |
+
================
|
3 |
+
|
4 |
+
Timeline express allows you to create a vertical animated and responsive timeline of posts , without writing a single line of code. Sweet!
|
5 |
+
|
6 |
+
**Features**
|
7 |
+
|
8 |
+
* Load a custom template for single announcements
|
9 |
+
* Localized date formatting for international users
|
10 |
+
* Hundreds of Font awesome icons included. Specify a different icon for each announcement
|
11 |
+
* CSS3 animations on scroll
|
12 |
+
* Set the color of the announcement
|
13 |
+
* Specify the length to trim each announcemnt, or randomize it!
|
14 |
+
* Hide the date of the announcement
|
15 |
+
* Hide the 'read more' button for each announcement
|
16 |
+
* Specify an image to display for each announcement
|
17 |
+
* Delete announcements on uninstallation (so no orphan posts are hanging around in your database)
|
18 |
+
* Easy to use shortcode to place the timeline wherever your heart desires ( `[timeline-express]` )
|
19 |
+
* TinyMCE button to generate the shortcode
|
20 |
+
* Specify Ascending vs Descending display order
|
21 |
+
* Highly extensible
|
22 |
+
* Translatable
|
23 |
+
|
24 |
+
**Translated**
|
25 |
+
|
26 |
+
Timeline express comes ready for translation. I would love to get things translated into as many languages as possible. At the moment the following translations are available for Timeline Express :
|
27 |
+
|
28 |
+
* English
|
29 |
+
* Chinese (zh_CN) - thanks goes to <a href="http://www.vahichen.com" target="_blank">Vahi Chen</a>
|
30 |
+
* Portuguese (pt_BR) - thanks goes to <a href="http://toborino.com" target="_blank">Gustavo Magalhães</a>
|
31 |
+
* Polish (pl_PL) - thanks goes to Kanios
|
32 |
+
* Dutch (nl_NL) - thanks goes to <a href="http://www.kasteelschaesberg.info/wpress/" target="_blank">Kees Hessels</a>
|
33 |
+
* German (de_DE) - thanks goes to <a href="http://www.fairsoft.koeln" target="_blank">Martin Gerlach</a>
|
34 |
+
* French (fr_FR) - thanks goes to Julien Lambert
|
35 |
+
|
36 |
+
<em>We're always looking for polyglots to help with the translations. If you enjoy this plugin, speak multiple languages and want to contribute please <a href="http://www.evan-herman.com/contact/" target="_blank">contact me</a> about how you can help translate things so users around the world can benefit from this plugin.</em>
|
37 |
+
|
38 |
+
**Hooks + Filters**
|
39 |
+
|
40 |
+
**Use Custom Images Instead of Font Awesome Icons (New v1.1.6.7)**
|
41 |
+
|
42 |
+
Users can now use the custom announcement image in place of the font awesome icons by using the following filter. Props to Pete Nelson for the pull request in making this possible
|
43 |
+
|
44 |
+
timeline-express-custom-icon-html
|
45 |
+
|
46 |
+
Example: https://gist.github.com/EvanHerman/6bbc8de82f34b4cb3c5c
|
47 |
+
|
48 |
+
**Use Alternate Image Size For Announcements (New v1.1.5.5)**
|
49 |
+
|
50 |
+
By default Timeline Express generates a custom image size to use within the timeline. If you would like to use another image size, you can use the following filter.
|
51 |
+
|
52 |
+
Example:
|
53 |
+
```<php>
|
54 |
+
function change_timeline_express_announcement_image_size( $image_size ) {
|
55 |
+
$image_size = 'full';
|
56 |
+
return $image_size;
|
57 |
+
}
|
58 |
+
add_filter( 'timeline-express-announcement-img-size' , 'change_timeline_express_announcement_image_size' );
|
59 |
+
```
|
60 |
+
|
61 |
+
**Define your own custom fields to use in Announcement posts (New v1.1.5)**
|
62 |
+
|
63 |
+
Users can now add custom fields to Timeline Express announcement posts. This allows for greater control over the announcements and the front end display. Using this hook in conjunction with a custom single announcement template will give you the greatest control.
|
64 |
+
|
65 |
+
Example:
|
66 |
+
```<php>
|
67 |
+
function add_custom_timeline_express_field( $custom_fields ) {
|
68 |
+
$custom_fields = array(
|
69 |
+
array(
|
70 |
+
'name' => __( 'Example Text Field', 'timeline-express' ),
|
71 |
+
'desc' => __( 'this is an example user defined text field.', 'timeline-express' ),
|
72 |
+
'id' => 'announcement_user_defined_text',
|
73 |
+
'type' => 'text_medium',
|
74 |
+
),
|
75 |
+
array(
|
76 |
+
'name' => __( 'Example WYSIWYG', 'timeline-express' ),
|
77 |
+
'desc' => __( 'this is an example wysiwyg field.', 'timeline-express' ),
|
78 |
+
'id' => 'announcement_user_defined_wysiwyg',
|
79 |
+
'type' => 'wysiwyg',
|
80 |
+
),
|
81 |
+
array(
|
82 |
+
'name' => __( 'Example Email Field', 'timeline-express' ),
|
83 |
+
'desc' => __( 'this is an example user defined email field.', 'timeline-express' ),
|
84 |
+
'id' => 'announcement_user_defined_money',
|
85 |
+
'type' => 'text_email',
|
86 |
+
)
|
87 |
+
);
|
88 |
+
return $custom_fields;
|
89 |
+
}
|
90 |
+
add_filter( 'timeline_express_custom_fields' , 'add_custom_timeline_express_field' );
|
91 |
+
```
|
92 |
+
|
93 |
+
This example would add 3 new fields below the 'Announcement Image' field on the announcement post.
|
94 |
+
|
95 |
+
The first field is a simple text field. The second field is an example WYSIWYG, and the third is an email field.
|
96 |
+
|
97 |
+
Note: You can add as many fields as you would like, and display them on the front end using the <a href="http://codex.wordpress.org/Function_Reference/get_post_meta" target="_blank" title="WordPress Codex: get_post_meta()">get_post_meta()</a> function.
|
98 |
+
|
99 |
+
**Customize the 'announcement' slug (New v1.1.4)**
|
100 |
+
|
101 |
+
Users can now define their own slug for announcement posts using the provided filter `'timeline-express-slug'`. This alters the URL structure of the announcement, possibly for SEO purposes. You would enter the following code into your active themes functions.php file.
|
102 |
+
|
103 |
+
After you enter the code into the functions.php file, you'll want to refresh your permalinks. You can do so by going to 'Settings > Permalinks' and simply clicking save. That will prevent the 404 page you may see upon altering the slug.
|
104 |
+
|
105 |
+
Example:
|
106 |
+
```<php>
|
107 |
+
// alter '/announcement/' to be '/event/'
|
108 |
+
function timeline_express_change_announcement_slug( $slug ) {
|
109 |
+
$slug = 'event';
|
110 |
+
return $slug;
|
111 |
+
}
|
112 |
+
add_filter('timeline-express-slug', 'timeline_express_change_announcement_slug' );
|
113 |
+
```
|
114 |
+
|
115 |
+
This example would change the default `/announcement/` slug, to `/event/`.
|
116 |
+
|
117 |
+
*Alter the 'Read More' button text (New v1.1.3.2)**
|
118 |
+
|
119 |
+
Users can now alter the 'Read More' button text using the provided gettext filter and the 'timeline-express' text domain.
|
120 |
+
|
121 |
+
Example:
|
122 |
+
```<php>
|
123 |
+
// alter 'Read more' to say 'View Announcement'
|
124 |
+
function timeline_express_change_readmore_text( $translated_text, $untranslated_text, $domain ) {
|
125 |
+
switch( $untranslated_text ) {
|
126 |
+
case 'Read more':
|
127 |
+
$translated_text = __( 'View Announcement','timeline-express' );
|
128 |
+
break;
|
129 |
+
}
|
130 |
+
return $translated_text;
|
131 |
+
}
|
132 |
+
add_filter('gettext', 'timeline_express_change_readmore_text', 20, 3);
|
133 |
+
```
|
134 |
+
|
135 |
+
This example would alter 'Read more' to say 'View Announcement'.
|
136 |
+
|
137 |
+
**Add custom classes to the 'Read More' button (New v1.1.3.1)**
|
138 |
+
|
139 |
+
Users can now add custom classes to the 'Read More' announcement button. This allows for greater control in fitting the Timeline into your currently active theme.
|
140 |
+
|
141 |
+
Parameters :
|
142 |
+
|
143 |
+
$button_classes = default button classes assigned to the 'Read More' button
|
144 |
+
|
145 |
+
Example:
|
146 |
+
```<php>
|
147 |
+
// add a custom class to the timeline express readmore link
|
148 |
+
function timeline_express_custom_readmore_class( $button_classes ) {
|
149 |
+
return $button_classes . 'custom-class-name';
|
150 |
+
}
|
151 |
+
add_filter( 'timeline-express-read-more-class' , 'timeline_express_custom_readmore_class' );
|
152 |
+
```
|
153 |
+
|
154 |
+
This example would print the following 'Read More' button HTML onto the page :
|
155 |
+
|
156 |
+
`<a href="http://site.com/link-to-announcement" class="cd-read-more btn btn-primary custom-class-name">Read more</a>`
|
157 |
+
|
158 |
+
**Setup a custom date format for front end display (New v1.0.9)**
|
159 |
+
|
160 |
+
New in version 1.0.9 is the localization of dates on the front end. The date format is now controlled by your date settings inside of 'General > Settings'.
|
161 |
+
|
162 |
+
If, for one reason or another, you'd like to specify a different date format than provided by WordPress core you can use the provided filter `timeline_express_custom_date_format`.
|
163 |
+
|
164 |
+
The one parameter you need to pass into your function is $date_format, which is (as it sounds) the format of the date.
|
165 |
+
|
166 |
+
Some formatting examples:
|
167 |
+
|
168 |
+
* `m.d.Y` - 11.19.2014
|
169 |
+
* `d-m-y` - 11-19-14
|
170 |
+
* `d M y` - 19 Nov 2014
|
171 |
+
* `D j/n/Y` - Wed 11/19/2014
|
172 |
+
* `l jS \of\ F` - Wednesday 19th of November
|
173 |
+
|
174 |
+
Example:
|
175 |
+
```<php>
|
176 |
+
function custom_te_date_format( $date_format ) {
|
177 |
+
$date_format = "M d , Y"; // will print the date as Nov 19 , 2014
|
178 |
+
return $date_format;
|
179 |
+
}
|
180 |
+
add_filter( 'timeline_express_custom_date_format' , 'custom_te_date_format' , 10 );
|
181 |
+
```
|
182 |
+
|
183 |
+
* d - Numeric representation of a day, with leading zeros 01 through 31.
|
184 |
+
* m - Numeric representation of a month, with leading zeros 01 through 12.
|
185 |
+
* y - Numeric representation of a year, two digits.
|
186 |
+
|
187 |
+
* D - Textual representation of a day, three letters Mon through Sun.
|
188 |
+
* j - Numeric representation of a day, without leading zeros 1 through 31.
|
189 |
+
* n - Numeric representation of a month, without leading zeros 1 through 12.
|
190 |
+
* Y - Numeric representation of a year, four digits.
|
191 |
+
|
192 |
+
* S - English ordinal suffix for the day of the month. Consist of 2 characters st, nd, rd or th.
|
193 |
+
* F - Textual representation of a month, January through December.
|
194 |
+
|
195 |
+
* M - Textual representation of a month, three letters Jan through Dec.
|
196 |
+
|
197 |
+
|
198 |
+
<em>[view more date formatting parameters](http://php.net/manual/en/function.date.php)</em>
|
199 |
+
|
200 |
+
|
201 |
+
**Load Your Own Single Announcement Template File (New v1.0.8)**
|
202 |
+
|
203 |
+
By default all single announcements will try and load a single.php template file. If that can't be found, we've done our best to implement a template for you. If your unhappy with the template file we've provided you have two options. Your first option is to copy over the single-announcement-template directory contained within the plugin into your active themes root. This will trigger the plugin to load that file instead. You can then customize this file to your hearts content without fear of losing any of your changes in the next update.
|
204 |
+
|
205 |
+
Your next option is to use our new filter for loading your own custom template file. If for whatever reason you've designed or developed your own single.php file which you would rather use, or you just want to use your themes page.php template instead, you can use the provided filter to change the loaded template. Here is an example ( you want to drop this code into your active theme's functions.php file ) :
|
206 |
+
|
207 |
+
Example:
|
208 |
+
```<php>
|
209 |
+
// By default Timeline Express uses single.php for announcements
|
210 |
+
// you can load page.php instead
|
211 |
+
// just change page.php to whatever your template file is named
|
212 |
+
// keep in mind, this is looking in your active themes root for the template
|
213 |
+
function custom_timeline_express_template_file( $template_file ) {
|
214 |
+
$template_file = 'page.php';
|
215 |
+
return $template_file;
|
216 |
+
}
|
217 |
+
add_filter( 'timeline_express_custom_template' , 'custom_timeline_express_template_file' , 10 );
|
218 |
+
```
|
219 |
+
|
220 |
+
<br />
|
221 |
+
<br />
|
222 |
+
<strong>While the plugins I develop are free, maintaining and supporting them is hard work. If you find this plugin useful, or it helps in anyway, please consider making a <a href="http://www.evan-herman.com/contact/?contact-reason=I%20want%20to%20make%20a%20donation%20for%20all%20your%20hard%20work">donation</a> for its continued development.</strong>
|
223 |
+
|
224 |
+
|
225 |
+
### Installation
|
226 |
+
|
227 |
+
1. Download the plugin .zip file
|
228 |
+
2. Log in to yourdomain.com/wp-admin
|
229 |
+
3. Click Plugins -> Add New -> Upload
|
230 |
+
4. Activate the plugin
|
231 |
+
6. On the left hand menu, hover over 'Timeline Express' and click 'New Announcement'
|
232 |
+
7. Begin populating the timeline with events. (Note: Events will appear in chronological order according to the <strong>announcement date</strong>)
|
233 |
+
8. Once you have populated the timeline, head over to the settings page (Settings > Timeline Express) to customize your timeline.
|
234 |
+
9. Create a new page, and enter the shortcode [timeline-express] to display the vertical timeline (Note: Timeline Express displays best on full width pages)
|
235 |
+
|
236 |
+
### Frequently Asked Questions
|
237 |
+
|
238 |
+
###### How do I use this plugin?
|
239 |
+
Begin by simply installing the plugin. Once the plugin has been installed, go ahead and begin creating announcement posts. You'll find a new menu item just below 'Posts'.
|
240 |
+
After you have a substantial number of announcements set up, you're ready to display the timeline on the front end of your site.
|
241 |
+
|
242 |
+
Timeline express displays best on full width pages, but is not limited to them. Create a new page, and drop the shortcode into the page - `[timeline-express]`.
|
243 |
+
Publish your page, and view it on the front end the see your new super sweet timeline! (scroll for animation effects!)
|
244 |
+
|
245 |
+
###### What template is the single announcement post using? Can I customize it at all? I want to do x, y or z.
|
246 |
+
The single announcement post is using a custom template file that comes pre-bundled with the plugin. If you want to customize the template for whatever reason
|
247 |
+
you can do so, by creating a directory in your active theme called 'timeline-express'. Once the directory is created, simply copy the file titled 'single-timeline-express-announcement.php' into
|
248 |
+
the newly created 'timeline-express' directory in your theme. Timeline express will then automagically pull in the newly created template in your theme root. You can go ahead and customize
|
249 |
+
it to your hearts desire without fear of losing any changes in future updates!
|
250 |
+
|
251 |
+
###### Can I create more than one timeline?
|
252 |
+
At the moment no, but I will consider adding that into a futre update if people show enough interest.
|
253 |
+
|
254 |
+
###### At what width are the breakpoints set?
|
255 |
+
Breakpoints are set at 822px. The timeline will shift/re-adjust automatically using masonry based on the height of each announcement container.
|
256 |
+
|
257 |
+
###### How can I translate this plugin?
|
258 |
+
The text-domain for all gettext functions is `timeline-express`.
|
259 |
+
|
260 |
+
If you enjoy this plugin and want to contribute, I'm always looking for people to help translate the plugin into any of the following languages, credit will be given where credit is due :
|
261 |
+
|
262 |
+
* Arabic
|
263 |
+
* English
|
264 |
+
* Greek
|
265 |
+
* Hebrew
|
266 |
+
* Hindi
|
267 |
+
* Hong Kong
|
268 |
+
* Italian
|
269 |
+
* Japanese
|
270 |
+
* Korean
|
271 |
+
* Persian
|
272 |
+
* Portuguese (European)
|
273 |
+
* Romanian
|
274 |
+
* Russian
|
275 |
+
* Spanish
|
276 |
+
* Swedish
|
277 |
+
* Taiwanese
|
278 |
+
* Tamil
|
279 |
+
* Urdu
|
280 |
+
* Vietnamese
|
281 |
+
* Welsh
|
282 |
+
|
283 |
+
Read the Codex article "[I18n for WordPress Developers]"(http://codex.wordpress.org/I18n_for_WordPress_Developers) for more information.
|
284 |
+
|
285 |
+
### Future Ideas
|
286 |
+
|
287 |
+
Have an idea for a future release feature? I love hearing about new ideas! You can get in contact with me through the contact form on my website, <a href="http://www.evan-herman.com/contact/" target="_blank">Evan-Herman.com</a>.
|
288 |
+
|
289 |
+
|
290 |
+
### Changelog
|
291 |
+
|
292 |
+
###### 1.1.6.5 - March 31st, 2015
|
293 |
+
* Enhancement: re-wrote part of the CSS file, to allow for native masonry layouts (uniform spacing between containers)
|
294 |
+
* Enhancement: Added `is_ssl()` check to determine if font awesome should be loaded over https or not.
|
295 |
+
* Fixed: Fixed WP_Response error when font-awesome icons are unavailable using `wp_remote_get();`
|
296 |
+
|
297 |
+
###### 1.1.6.4 - March 23rd, 2015
|
298 |
+
* Enhancement: Packaged French translation - thanks goes to Julien Lambert
|
299 |
+
* Enhancement: Fixed a few typos in the plugin
|
300 |
+
|
301 |
+
###### 1.1.6.3 - March 22nd, 2015
|
302 |
+
* Enhancement: Added wp_error class to catch errors thrown by `wp_remote_get()` when building the bootstrap dropdown.
|
303 |
+
|
304 |
+
###### 1.1.6.2 - March 18th, 2015
|
305 |
+
* Enhancement: Removed `add_option();` call which was breaking previously stored options on activation
|
306 |
+
|
307 |
+
###### 1.1.6.1 - March 10th, 2015
|
308 |
+
* Enhancement: Altered new option label to be 'Exclude Announcements from Site Searches' (settings were reversed (true excluded while false included) )
|
309 |
+
|
310 |
+
###### 1.1.6 - March 9th, 2015
|
311 |
+
* Enhancement: Fixed 404 issue on announcement posts when 'Include Announcement in Site Searches' was set to 'false'.
|
312 |
+
|
313 |
+
###### 1.1.5.9 - March 6th, 2015
|
314 |
+
* Enhancement: Added a priority to the metabox initialization, which caused conflicts with other plugins using the same class
|
315 |
+
|
316 |
+
###### 1.1.5.8 - March 5th, 2015
|
317 |
+
* Enhancement: Upgraded font-awesome to 4.3.0
|
318 |
+
* Enhancement: Added icon select dropdown on the settings page, to better mirror the post/page edit screens
|
319 |
+
* Enhancement: Added new setting to toggle Timeline posts from appearing in search queries on the front end (defaults to true)
|
320 |
+
* Enhancement: Packaged German translation - thanks to <a href="http://www.fairsoft.koeln" target="_blank">Martin Gerlach</a>
|
321 |
+
|
322 |
+
###### 1.1.5.7 - February 5th, 2015
|
323 |
+
* Message From The Author: Sorry for multiple updates on the same day. I was feeling ambitious and rolled out one patch to fix an issue and another with some new features. Enjoy :)
|
324 |
+
* Enhancement: Added a dropdown to select the font awesome icon
|
325 |
+
* Enhancement: Fadded in the timeline after everything has initialized, to prevent seeing a messed up Timeline layout
|
326 |
+
|
327 |
+
###### 1.1.5.6 - February 5th, 2015
|
328 |
+
* Fixed: Issue with the excerpt being truncated and throwing off entire timeline layout (issue occured when truncate happened mid html tag , which left a tag open)
|
329 |
+
* Fixed: Wrapped missing text in text domain
|
330 |
+
|
331 |
+
###### 1.1.5.5 - February 1st, 2015
|
332 |
+
* Fixed: Wrapped admin column headers in get text filter
|
333 |
+
* Fixed: Sort orders by announcement date
|
334 |
+
* Enhancement: Added filter to define custom image size for announcement image
|
335 |
+
|
336 |
+
###### 1.1.5.4 - January 19th, 2015
|
337 |
+
* Fixed: Remove unnecessary filter in the main class file
|
338 |
+
|
339 |
+
###### 1.1.5.3 - January 16th, 2015
|
340 |
+
* Fixed: Fixed incorrect date save format
|
341 |
+
|
342 |
+
###### 1.1.5.2 - January 10th, 2015
|
343 |
+
Fixed: Errors thrown from new user fields hook, when no custom fields are defined by the user
|
344 |
+
Fixed: Incorrect date format for new announcements
|
345 |
+
|
346 |
+
###### 1.1.5.1 - January 10th, 2015
|
347 |
+
* Fixed: Data saving incorrectly to the database, causing errors to be thrown on front and back end
|
348 |
+
|
349 |
+
###### 1.1.5 - January 10th, 2015
|
350 |
+
* Enhancement: Added new filter ( `timeline_express_custom_fields` ) which allows users to define their own custom fields to use on Timeline Announcement posts (see readme for example).
|
351 |
+
* Fixed: CMB class file causing conflicts with other plugins, and removed the old version
|
352 |
+
* Fixed: Adjusted a few styles on the announcement post page
|
353 |
+
|
354 |
+
###### 1.1.4.1 - January 2nd, 2015
|
355 |
+
* Fixed: Issue with date storing different on backend vs front end
|
356 |
+
* Fixed: Settings link on the Timeline Express welcome page
|
357 |
+
|
358 |
+
###### 1.1.4 - December 24th, 2014
|
359 |
+
* Enhancement: Implemented premium support licensing. Any issues that require immediate response, or custom code should purchase a support license.
|
360 |
+
* Enhancement: Moved settings/support below Timeline Express parent menu item
|
361 |
+
* Fixed: Errors thrown when announcement images aren't set
|
362 |
+
* Fixed: Display error where announcements displayed a different date on the backend vs frontend
|
363 |
+
* Enhancement: Added a new filter to customize the announcement slug (possibly for SEO purposes) (timeline-express-slug , check documentation for examples)
|
364 |
+
|
365 |
+
###### 1.1.3.2 - December 11th, 2014
|
366 |
+
* Enhancement: Added Dutch language translation (nl_NL) - thanks goes to <a href="http://www.kasteelschaesberg.info/wpress/" target="_blank">Kees Hessels</a>
|
367 |
+
* Fixed: A few typos throughout the plugin
|
368 |
+
|
369 |
+
###### 1.1.3.1 - December 10th, 2014
|
370 |
+
* Enhancement: Added new filter `timeline-express-read-more-class` which allows users to add custom classes to the 'Read More' button
|
371 |
+
* Enhancement: Wrapped 'Read More' in gettext filter, to allow for text to be altered
|
372 |
+
|
373 |
+
###### 1.1.3 - December 6th, 2014
|
374 |
+
* Fixed: Weird query issue with timeline announcements not displaying at proper times
|
375 |
+
* Fixed: Styling issue with announcement date picker calendar arrow
|
376 |
+
* Fixed: Removed all line-breaks and hyphens from the timeline titles
|
377 |
+
|
378 |
+
###### 1.1.2 - December 5th, 2014
|
379 |
+
* Fixed: Minor styling issues with announcement images extending outside the announcement container (added new class to the image .announcement-banner-image)
|
380 |
+
|
381 |
+
###### 1.1.1 - December 4th, 2014
|
382 |
+
* Fixed: Minor styling issues with the mobile timeline icon size/margins
|
383 |
+
* Fixed: Minor styling issues with the mobile timeline announcement arrow appearing 1px to soon
|
384 |
+
* Fixed: Typo of 'Timeline Express' in the admin settings menu
|
385 |
+
|
386 |
+
###### 1.1 - December 3rd, 2014
|
387 |
+
* Fixed: Fixed styles when timeline is inside posts (fixed icon size, duplicate images)
|
388 |
+
* Fixed: Fixed a few enqueue functions
|
389 |
+
* Enhancement: Polish language translation now included (pl_PL) - thanks goes to Kanios
|
390 |
+
* Enhancement: Enqueued new styles on single announcement posts to style the announcement pages a bit better
|
391 |
+
* Enhancement: Added new custom image size, to unify announcement images on the timeline ('timeline-express')
|
392 |
+
* Enhancement: Added new function `timeline_express_get_image_id()` to get attachment image IDs by URL
|
393 |
+
* Enhancement: Stripped out a lot of un-needed code
|
394 |
+
|
395 |
+
###### 1.0.9 - November 19th, 2014
|
396 |
+
* Updated: Localized date format displayed on the front end as requested by our international users ( format now takes on what you have in 'General > Settings' )
|
397 |
+
* Updated: Fixed styling issue on date picker arrows
|
398 |
+
* Feature: Added new filter to allow users to specify a custom date format (`timeline_express_custom_date_format`)
|
399 |
+
|
400 |
+
###### 1.0.8 - November 17th, 2014
|
401 |
+
* Feature: Added a new filter to allow users to load custom template files
|
402 |
+
* Feature: Added auto update feature for Timeline Express
|
403 |
+
* Updated: Single announcement template file, which was causing issues for some users on specific themes
|
404 |
+
* Fixed: Issue where links in the excerpt and 'read more' links couldn't be clicked due to overlapping masonry elements
|
405 |
+
* Fixed: Missing image on welcome page
|
406 |
+
* Fixed: Minor issues on welcome page including some links
|
407 |
+
|
408 |
+
###### 1.0.7 - November 13th, 2014
|
409 |
+
* Enhancement: Portuguese language translation now included (pt_BR) - thanks goes to <a href="http://toborino.com" target="_blank">Gustavo Magalhães</a>
|
410 |
+
|
411 |
+
###### 1.0.6
|
412 |
+
* Repaired fatal error thrown on activation for sites running older versions of PHP
|
413 |
+
|
414 |
+
###### 1.0.5
|
415 |
+
* Change priority argument on register post type function, which caused conflicts with other custom post types on certain sites
|
416 |
+
|
417 |
+
###### 1.0.4
|
418 |
+
* Chinese language translation now included (zh_CN) - thanks goes to <a href="http://www.vahichen.com" target="_blank">Vahi Chen</a>
|
419 |
+
* Removed title and content style declarations for font-size and font-family styles
|
420 |
+
|
421 |
+
###### 1.0.3
|
422 |
+
* Included new function to retain formatting in the announcement excerpt in the timeline (te_wp_trim_words_retain_formatting())
|
423 |
+
|
424 |
+
###### 1.0.2
|
425 |
+
* Add display order setting to specify ascending or descending order of announcements in the timeline
|
426 |
+
* Fixed "cannot access settings page" when clicking on the settings tab when on the settings page already
|
427 |
+
|
428 |
+
###### 1.0.1
|
429 |
+
* Update masonry function to include .imagesLoaded(); to prevent overlapping containers in the timeline
|
430 |
+
|
431 |
+
###### 1.0
|
432 |
+
* Initial Release to the WordPress repository
|
classes/class.timeline-express.php
CHANGED
@@ -466,7 +466,7 @@ if(!class_exists("timelineExpressBase"))
|
|
466 |
'show_in_nav_menus' => true,
|
467 |
'show_in_admin_bar' => true,
|
468 |
'menu_position' => 5,
|
469 |
-
'menu_icon' => TIMELINE_EXPRESS_URL . '
|
470 |
'can_export' => true,
|
471 |
'has_archive' => true,
|
472 |
'exclude_from_search' => $announcements_public, // toggled via setitngs page - @since v1.1.5.8,
|
@@ -1055,17 +1055,25 @@ if(!class_exists("timelineExpressBase"))
|
|
1055 |
?>
|
1056 |
<div class="cd-timeline-block">
|
1057 |
<!-- icon -->
|
1058 |
-
<?php
|
1059 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1060 |
<div class="cd-timeline-img cd-picture" style="background:<?php echo get_post_meta( $post->ID , 'announcement_color' , true ); ?>;">
|
1061 |
<span class="fa <?php echo get_post_meta( $post->ID , 'announcement_icon' , true ); ?>" title="<?php echo get_the_title( $post->ID ); ?>"></span>
|
1062 |
</div> <!-- cd-timeline-img -->
|
1063 |
-
|
1064 |
-
<?php }
|
1065 |
-
<div class="cd-timeline-img cd-picture" style="background:<?php echo get_post_meta( $post->ID , 'announcement_color' , true ); ?>;">
|
1066 |
-
<span class="fa <?php echo get_post_meta( $post->ID , 'announcement_icon' , true ); ?>" title="<?php echo get_the_title( $post->ID ); ?>"></span>
|
1067 |
-
</div> <!-- cd-timeline-img -->
|
1068 |
-
<?php } ?>
|
1069 |
<!-- content/date/etc. -->
|
1070 |
<div class="cd-timeline-content" style="background:<?php if ( $content_background == '' ) { echo 'transparent'; } else { echo $content_background; } ?>;box-shadow: 0 3px 0 <?php if ( $content_shadow == '' ) { echo 'transparent'; } else { echo $content_shadow; } ?>;">
|
1071 |
<!-- title -->
|
@@ -1306,7 +1314,7 @@ if(!class_exists("timelineExpressBase"))
|
|
1306 |
}
|
1307 |
|
1308 |
wp_enqueue_script( 'bootstrap-select' , TIMELINE_EXPRESS_URL . 'js/bootstrap-select.js' , array( 'jquery' ) , 'all' );
|
1309 |
-
wp_enqueue_script( 'bootstrap-min' , '
|
1310 |
wp_enqueue_style('bootstrap-select-style' , TIMELINE_EXPRESS_URL . 'css/bootstrap-select.min.css' );
|
1311 |
?>
|
1312 |
<script>
|
466 |
'show_in_nav_menus' => true,
|
467 |
'show_in_admin_bar' => true,
|
468 |
'menu_position' => 5,
|
469 |
+
'menu_icon' => TIMELINE_EXPRESS_URL . 'images/timeline-express-menu-icon.png',
|
470 |
'can_export' => true,
|
471 |
'has_archive' => true,
|
472 |
'exclude_from_search' => $announcements_public, // toggled via setitngs page - @since v1.1.5.8,
|
1055 |
?>
|
1056 |
<div class="cd-timeline-block">
|
1057 |
<!-- icon -->
|
1058 |
+
<?php
|
1059 |
+
// allow an override of the default Font Awesome icon
|
1060 |
+
$custom_icon_html = apply_filters( 'timeline-express-custom-icon-html', '', $post, $this->timeline_express_optionVal );
|
1061 |
+
if ( ! empty( $custom_icon_html) ) {
|
1062 |
+
echo $custom_icon_html;
|
1063 |
+
} else {
|
1064 |
+
?>
|
1065 |
+
<?php if ( $this->timeline_express_optionVal['read-more-visibility'] != 0 ) { ?>
|
1066 |
+
<a class="cd-timeline-icon-link" href="<?php echo get_the_permalink( $post->ID ); ?>">
|
1067 |
+
<div class="cd-timeline-img cd-picture" style="background:<?php echo get_post_meta( $post->ID , 'announcement_color' , true ); ?>;">
|
1068 |
+
<span class="fa <?php echo get_post_meta( $post->ID , 'announcement_icon' , true ); ?>" title="<?php echo get_the_title( $post->ID ); ?>"></span>
|
1069 |
+
</div> <!-- cd-timeline-img -->
|
1070 |
+
</a>
|
1071 |
+
<?php } else { ?>
|
1072 |
<div class="cd-timeline-img cd-picture" style="background:<?php echo get_post_meta( $post->ID , 'announcement_color' , true ); ?>;">
|
1073 |
<span class="fa <?php echo get_post_meta( $post->ID , 'announcement_icon' , true ); ?>" title="<?php echo get_the_title( $post->ID ); ?>"></span>
|
1074 |
</div> <!-- cd-timeline-img -->
|
1075 |
+
<?php } ?>
|
1076 |
+
<?php } // endif for $custom_icon_html check ?>
|
|
|
|
|
|
|
|
|
1077 |
<!-- content/date/etc. -->
|
1078 |
<div class="cd-timeline-content" style="background:<?php if ( $content_background == '' ) { echo 'transparent'; } else { echo $content_background; } ?>;box-shadow: 0 3px 0 <?php if ( $content_shadow == '' ) { echo 'transparent'; } else { echo $content_shadow; } ?>;">
|
1079 |
<!-- title -->
|
1314 |
}
|
1315 |
|
1316 |
wp_enqueue_script( 'bootstrap-select' , TIMELINE_EXPRESS_URL . 'js/bootstrap-select.js' , array( 'jquery' ) , 'all' );
|
1317 |
+
wp_enqueue_script( 'bootstrap-min' , '//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js' );
|
1318 |
wp_enqueue_style('bootstrap-select-style' , TIMELINE_EXPRESS_URL . 'css/bootstrap-select.min.css' );
|
1319 |
?>
|
1320 |
<script>
|
css/timeline-express-css3-slideshow.css
CHANGED
@@ -1,143 +1,143 @@
|
|
1 |
-
#slides {
|
2 |
-
display: none
|
3 |
-
}
|
4 |
-
|
5 |
-
#slides .slidesjs-navigation {
|
6 |
-
margin-top:5px;
|
7 |
-
}
|
8 |
-
|
9 |
-
a.slidesjs-next,
|
10 |
-
a.slidesjs-previous,
|
11 |
-
a.slidesjs-play,
|
12 |
-
a.slidesjs-stop {
|
13 |
-
display: none !important;
|
14 |
-
}
|
15 |
-
|
16 |
-
a.slidesjs-next {
|
17 |
-
margin-right:10px;
|
18 |
-
background-position: -12px 0;
|
19 |
-
}
|
20 |
-
|
21 |
-
a:hover.slidesjs-next {
|
22 |
-
background-position: -12px -18px;
|
23 |
-
}
|
24 |
-
|
25 |
-
a.slidesjs-previous {
|
26 |
-
background-position: 0 0;
|
27 |
-
}
|
28 |
-
|
29 |
-
a:hover.slidesjs-previous {
|
30 |
-
background-position: 0 -18px;
|
31 |
-
}
|
32 |
-
|
33 |
-
a.slidesjs-play {
|
34 |
-
width:15px;
|
35 |
-
background-position: -25px 0;
|
36 |
-
}
|
37 |
-
|
38 |
-
a:hover.slidesjs-play {
|
39 |
-
background-position: -25px -18px;
|
40 |
-
}
|
41 |
-
|
42 |
-
a.slidesjs-stop {
|
43 |
-
width:18px;
|
44 |
-
background-position: -41px 0;
|
45 |
-
}
|
46 |
-
|
47 |
-
a:hover.slidesjs-stop {
|
48 |
-
background-position: -41px -18px;
|
49 |
-
}
|
50 |
-
|
51 |
-
.slidesjs-pagination {
|
52 |
-
margin: 7px 0 0;
|
53 |
-
float: right;
|
54 |
-
list-style: none;
|
55 |
-
}
|
56 |
-
|
57 |
-
.slidesjs-pagination li {
|
58 |
-
float: left;
|
59 |
-
margin: 0 1px;
|
60 |
-
}
|
61 |
-
|
62 |
-
.slidesjs-pagination li a {
|
63 |
-
display: block;
|
64 |
-
width: 13px;
|
65 |
-
height: 0;
|
66 |
-
padding-top: 13px;
|
67 |
-
background-image: url(../images/support/pagination.png);
|
68 |
-
background-position: 0 0;
|
69 |
-
float: left;
|
70 |
-
overflow: hidden;
|
71 |
-
}
|
72 |
-
|
73 |
-
.slidesjs-pagination li a.active,
|
74 |
-
.slidesjs-pagination li a:hover.active {
|
75 |
-
background-position: 0 -13px
|
76 |
-
}
|
77 |
-
|
78 |
-
.slidesjs-pagination li a:hover {
|
79 |
-
background-position: 0 -26px
|
80 |
-
}
|
81 |
-
|
82 |
-
#slides a:link,
|
83 |
-
#slides a:visited {
|
84 |
-
color: #333
|
85 |
-
}
|
86 |
-
|
87 |
-
#slides a:hover,
|
88 |
-
#slides a:active {
|
89 |
-
color: #9e2020
|
90 |
-
}
|
91 |
-
|
92 |
-
.navbar {
|
93 |
-
overflow: hidden
|
94 |
-
}
|
95 |
-
#slides {
|
96 |
-
display: none
|
97 |
-
}
|
98 |
-
|
99 |
-
.te-slider-container {
|
100 |
-
margin: 0 auto
|
101 |
-
}
|
102 |
-
|
103 |
-
/* For tablets & smart phones */
|
104 |
-
@media (max-width: 767px) {
|
105 |
-
.te-slider-container {
|
106 |
-
width: auto;
|
107 |
-
left: 0;
|
108 |
-
}
|
109 |
-
}
|
110 |
-
|
111 |
-
/* For smartphones */
|
112 |
-
@media (max-width: 480px) {
|
113 |
-
.te-slider-container {
|
114 |
-
width: auto;
|
115 |
-
}
|
116 |
-
}
|
117 |
-
|
118 |
-
/* For smaller displays like laptops */
|
119 |
-
@media (min-width: 768px) and (max-width: 979px) {
|
120 |
-
.te-slider-container {
|
121 |
-
width: 724px;
|
122 |
-
}
|
123 |
-
}
|
124 |
-
|
125 |
-
/* For larger displays */
|
126 |
-
@media (min-width: 1200px) {
|
127 |
-
.te-slider-container {
|
128 |
-
position: absolute;
|
129 |
-
right: 0;
|
130 |
-
top: 0;
|
131 |
-
margin: 1.3em 2em 0 0;
|
132 |
-
width: 650px;
|
133 |
-
height: 165px;
|
134 |
-
}
|
135 |
-
}
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
|
1 |
+
#slides {
|
2 |
+
display: none
|
3 |
+
}
|
4 |
+
|
5 |
+
#slides .slidesjs-navigation {
|
6 |
+
margin-top:5px;
|
7 |
+
}
|
8 |
+
|
9 |
+
a.slidesjs-next,
|
10 |
+
a.slidesjs-previous,
|
11 |
+
a.slidesjs-play,
|
12 |
+
a.slidesjs-stop {
|
13 |
+
display: none !important;
|
14 |
+
}
|
15 |
+
|
16 |
+
a.slidesjs-next {
|
17 |
+
margin-right:10px;
|
18 |
+
background-position: -12px 0;
|
19 |
+
}
|
20 |
+
|
21 |
+
a:hover.slidesjs-next {
|
22 |
+
background-position: -12px -18px;
|
23 |
+
}
|
24 |
+
|
25 |
+
a.slidesjs-previous {
|
26 |
+
background-position: 0 0;
|
27 |
+
}
|
28 |
+
|
29 |
+
a:hover.slidesjs-previous {
|
30 |
+
background-position: 0 -18px;
|
31 |
+
}
|
32 |
+
|
33 |
+
a.slidesjs-play {
|
34 |
+
width:15px;
|
35 |
+
background-position: -25px 0;
|
36 |
+
}
|
37 |
+
|
38 |
+
a:hover.slidesjs-play {
|
39 |
+
background-position: -25px -18px;
|
40 |
+
}
|
41 |
+
|
42 |
+
a.slidesjs-stop {
|
43 |
+
width:18px;
|
44 |
+
background-position: -41px 0;
|
45 |
+
}
|
46 |
+
|
47 |
+
a:hover.slidesjs-stop {
|
48 |
+
background-position: -41px -18px;
|
49 |
+
}
|
50 |
+
|
51 |
+
.slidesjs-pagination {
|
52 |
+
margin: 7px 0 0;
|
53 |
+
float: right;
|
54 |
+
list-style: none;
|
55 |
+
}
|
56 |
+
|
57 |
+
.slidesjs-pagination li {
|
58 |
+
float: left;
|
59 |
+
margin: 0 1px;
|
60 |
+
}
|
61 |
+
|
62 |
+
.slidesjs-pagination li a {
|
63 |
+
display: block;
|
64 |
+
width: 13px;
|
65 |
+
height: 0;
|
66 |
+
padding-top: 13px;
|
67 |
+
background-image: url(../images/support/pagination.png);
|
68 |
+
background-position: 0 0;
|
69 |
+
float: left;
|
70 |
+
overflow: hidden;
|
71 |
+
}
|
72 |
+
|
73 |
+
.slidesjs-pagination li a.active,
|
74 |
+
.slidesjs-pagination li a:hover.active {
|
75 |
+
background-position: 0 -13px
|
76 |
+
}
|
77 |
+
|
78 |
+
.slidesjs-pagination li a:hover {
|
79 |
+
background-position: 0 -26px
|
80 |
+
}
|
81 |
+
|
82 |
+
#slides a:link,
|
83 |
+
#slides a:visited {
|
84 |
+
color: #333
|
85 |
+
}
|
86 |
+
|
87 |
+
#slides a:hover,
|
88 |
+
#slides a:active {
|
89 |
+
color: #9e2020
|
90 |
+
}
|
91 |
+
|
92 |
+
.navbar {
|
93 |
+
overflow: hidden
|
94 |
+
}
|
95 |
+
#slides {
|
96 |
+
display: none
|
97 |
+
}
|
98 |
+
|
99 |
+
.te-slider-container {
|
100 |
+
margin: 0 auto
|
101 |
+
}
|
102 |
+
|
103 |
+
/* For tablets & smart phones */
|
104 |
+
@media (max-width: 767px) {
|
105 |
+
.te-slider-container {
|
106 |
+
width: auto;
|
107 |
+
left: 0;
|
108 |
+
}
|
109 |
+
}
|
110 |
+
|
111 |
+
/* For smartphones */
|
112 |
+
@media (max-width: 480px) {
|
113 |
+
.te-slider-container {
|
114 |
+
width: auto;
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
/* For smaller displays like laptops */
|
119 |
+
@media (min-width: 768px) and (max-width: 979px) {
|
120 |
+
.te-slider-container {
|
121 |
+
width: 724px;
|
122 |
+
}
|
123 |
+
}
|
124 |
+
|
125 |
+
/* For larger displays */
|
126 |
+
@media (min-width: 1200px) {
|
127 |
+
.te-slider-container {
|
128 |
+
position: absolute;
|
129 |
+
right: 0;
|
130 |
+
top: 0;
|
131 |
+
margin: 1.3em 2em 0 0;
|
132 |
+
width: 650px;
|
133 |
+
height: 165px;
|
134 |
+
}
|
135 |
+
}
|
136 |
+
|
137 |
+
|
138 |
+
|
139 |
+
|
140 |
+
|
141 |
+
|
142 |
+
|
143 |
|
css/timeline-express-single-page.css
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
-
/* Single-te_announcements Styles */
|
2 |
-
.single-te_announcements img.announcement-banner-image {
|
3 |
-
float: left;
|
4 |
-
margin: 5px 15px 15px 0;
|
5 |
}
|
1 |
+
/* Single-te_announcements Styles */
|
2 |
+
.single-te_announcements img.announcement-banner-image {
|
3 |
+
float: left;
|
4 |
+
margin: 5px 15px 15px 0;
|
5 |
}
|
languages/timeline-express-it_IT.mo
ADDED
Binary file
|
languages/timeline-express-it_IT.po
ADDED
@@ -0,0 +1,839 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright (C) 2015 Timeline Express
|
2 |
+
# This file is distributed under the same license as the Timeline Express package.
|
3 |
+
msgid ""
|
4 |
+
msgstr ""
|
5 |
+
"Project-Id-Version: Timeline Express 1.1.6.3\n"
|
6 |
+
"Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/timeline-express\n"
|
7 |
+
"POT-Creation-Date: 2015-03-22 21:23:33+00:00\n"
|
8 |
+
"MIME-Version: 1.0\n"
|
9 |
+
"Content-Type: text/plain; charset=UTF-8\n"
|
10 |
+
"Content-Transfer-Encoding: 8bit\n"
|
11 |
+
"PO-Revision-Date: 2015-05-01 00:08+0100\n"
|
12 |
+
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
13 |
+
"Last-Translator: Eva <eva.filoramo@gmail.com>\n"
|
14 |
+
"Language-Team: \n"
|
15 |
+
"Language: it\n"
|
16 |
+
"X-Generator: Poedit 1.7.6\n"
|
17 |
+
|
18 |
+
#: classes/class.timeline-express.php:436
|
19 |
+
msgid "Timeline Express Announcements"
|
20 |
+
msgstr "Annunci Timeline Express"
|
21 |
+
|
22 |
+
#: classes/class.timeline-express.php:437
|
23 |
+
msgid "Announcement"
|
24 |
+
msgstr "Annuncio"
|
25 |
+
|
26 |
+
#. Plugin Name of the plugin/theme
|
27 |
+
#: classes/class.timeline-express.php:438
|
28 |
+
msgid "Timeline Express"
|
29 |
+
msgstr "Timeline Express"
|
30 |
+
|
31 |
+
#: classes/class.timeline-express.php:439
|
32 |
+
msgid "Timeline Express:"
|
33 |
+
msgstr "Timeline Express:"
|
34 |
+
|
35 |
+
#: classes/class.timeline-express.php:440
|
36 |
+
msgid "All Announcements"
|
37 |
+
msgstr "Tutti gli annunci"
|
38 |
+
|
39 |
+
#: classes/class.timeline-express.php:441
|
40 |
+
msgid "View Announcement"
|
41 |
+
msgstr "Vedi l'annuncio"
|
42 |
+
|
43 |
+
#: classes/class.timeline-express.php:442 classes/class.timeline-express.php:443
|
44 |
+
msgid "New Announcement"
|
45 |
+
msgstr "Nuovo annuncio"
|
46 |
+
|
47 |
+
#: classes/class.timeline-express.php:444
|
48 |
+
msgid "Edit Announcement"
|
49 |
+
msgstr "Modifica l'annuncio"
|
50 |
+
|
51 |
+
#: classes/class.timeline-express.php:445
|
52 |
+
msgid "Update Announcement"
|
53 |
+
msgstr "Aggiorna l'annuncio"
|
54 |
+
|
55 |
+
#: classes/class.timeline-express.php:446
|
56 |
+
msgid "Search Announcements"
|
57 |
+
msgstr "Cerca un annuncio"
|
58 |
+
|
59 |
+
#: classes/class.timeline-express.php:447
|
60 |
+
msgid "No Timeline Express Announcements Found"
|
61 |
+
msgstr "Non è stato trovato nessun annuncio Timeline Express"
|
62 |
+
|
63 |
+
#: classes/class.timeline-express.php:448
|
64 |
+
msgid "No Timeline Express Announcements in Trash"
|
65 |
+
msgstr "Non c'è nessun annuncio Timeline Express nel cestino"
|
66 |
+
|
67 |
+
#: classes/class.timeline-express.php:458
|
68 |
+
msgid "Post type for adding timeline express announcements to the site"
|
69 |
+
msgstr "Tipo di post per aggiungere annunci"
|
70 |
+
|
71 |
+
#: classes/class.timeline-express.php:508
|
72 |
+
msgid "Announcement Color"
|
73 |
+
msgstr "Colore dell'annuncio"
|
74 |
+
|
75 |
+
#: classes/class.timeline-express.php:509
|
76 |
+
msgid "select the color for this announcement."
|
77 |
+
msgstr "seleziona il colore di questo annuncio"
|
78 |
+
|
79 |
+
#: classes/class.timeline-express.php:517
|
80 |
+
msgid "Announcement Icon"
|
81 |
+
msgstr "Icona dell'annuncio"
|
82 |
+
|
83 |
+
#: classes/class.timeline-express.php:518
|
84 |
+
msgid ""
|
85 |
+
"select an icon from the drop down above. This is used for the icon associated "
|
86 |
+
"with the announcement."
|
87 |
+
msgstr ""
|
88 |
+
"seleziona un'icona dal menu a tendina. Sarà usata come icona associata "
|
89 |
+
"all'annuncio."
|
90 |
+
|
91 |
+
#: classes/class.timeline-express.php:526 classes/class.timeline-express.php:821
|
92 |
+
#: classes/class.timeline-express.php:828
|
93 |
+
msgid "Announcement Date"
|
94 |
+
msgstr "Data dell'annuncio"
|
95 |
+
|
96 |
+
#: classes/class.timeline-express.php:527
|
97 |
+
msgid ""
|
98 |
+
"enter the date of the announcement. the announcements will appear in "
|
99 |
+
"chronological order according to this date. "
|
100 |
+
msgstr ""
|
101 |
+
"inserisci la data dell'annuncio. Gli annunci compariranno in ordine cronologico "
|
102 |
+
"secondo questa data."
|
103 |
+
|
104 |
+
#: classes/class.timeline-express.php:535
|
105 |
+
msgid "Announcement Image"
|
106 |
+
msgstr "Immagine dell'annuncio"
|
107 |
+
|
108 |
+
#: classes/class.timeline-express.php:536
|
109 |
+
msgid ""
|
110 |
+
"select a banner image for this announcement (optional). (recommended 650px wide "
|
111 |
+
"or larger) "
|
112 |
+
msgstr ""
|
113 |
+
"seleziona un'immagine banner per questo annuncio (opzionale). (dimensione "
|
114 |
+
"consigliata: 650px di larghezza e oltre)"
|
115 |
+
|
116 |
+
#: classes/class.timeline-express.php:560
|
117 |
+
msgid "Announcement Info."
|
118 |
+
msgstr "Info sull'annuncio"
|
119 |
+
|
120 |
+
#: classes/class.timeline-express.php:571
|
121 |
+
msgid "About"
|
122 |
+
msgstr "About"
|
123 |
+
|
124 |
+
#: classes/class.timeline-express.php:598
|
125 |
+
msgid "Enter Announcement Title"
|
126 |
+
msgstr "Inserire il titolo dell'annuncio"
|
127 |
+
|
128 |
+
#: classes/class.timeline-express.php:606
|
129 |
+
msgctxt "timeline-express"
|
130 |
+
msgid "Announcement Name"
|
131 |
+
msgstr "Nome dell'annuncio"
|
132 |
+
|
133 |
+
#: classes/class.timeline-express.php:607
|
134 |
+
msgctxt "timeline-express"
|
135 |
+
msgid "Color"
|
136 |
+
msgstr "Colore"
|
137 |
+
|
138 |
+
#: classes/class.timeline-express.php:608
|
139 |
+
msgctxt "timeline-express"
|
140 |
+
msgid "Icon"
|
141 |
+
msgstr "Icona"
|
142 |
+
|
143 |
+
#: classes/class.timeline-express.php:609
|
144 |
+
msgctxt "timeline-express"
|
145 |
+
msgid "Announcement Date"
|
146 |
+
msgstr "Data dell'annuncio"
|
147 |
+
|
148 |
+
#: classes/class.timeline-express.php:610
|
149 |
+
msgctxt "timeline-express"
|
150 |
+
msgid "Image"
|
151 |
+
msgstr "Immagine"
|
152 |
+
|
153 |
+
#: classes/class.timeline-express.php:611
|
154 |
+
msgctxt "timeline-express"
|
155 |
+
msgid "Announcment Past?"
|
156 |
+
msgstr "Annuncio passato?"
|
157 |
+
|
158 |
+
#: classes/class.timeline-express.php:824 classes/class.timeline-express.php:831
|
159 |
+
msgid "Back"
|
160 |
+
msgstr "Indietro"
|
161 |
+
|
162 |
+
#: classes/class.timeline-express.php:1097
|
163 |
+
#: classes/class.timeline-express.php:1104
|
164 |
+
#: classes/class.timeline-express.php:1118
|
165 |
+
msgid "..."
|
166 |
+
msgstr "..."
|
167 |
+
|
168 |
+
#: classes/class.timeline-express.php:1105
|
169 |
+
#: classes/class.timeline-express.php:1119
|
170 |
+
msgid "Read more"
|
171 |
+
msgstr "Leggi oltre"
|
172 |
+
|
173 |
+
#: classes/class.timeline-express.php:1347 pages/options.php:171
|
174 |
+
msgid "Timeline Express Settings"
|
175 |
+
msgstr "Impostazioni di Timeline Express"
|
176 |
+
|
177 |
+
#: classes/class.timeline-express.php:1347
|
178 |
+
msgid "Settings"
|
179 |
+
msgstr "Impostazioni"
|
180 |
+
|
181 |
+
#: classes/class.timeline-express.php:1349
|
182 |
+
msgid "Timeline Express Welcome"
|
183 |
+
msgstr "Benvenuto"
|
184 |
+
|
185 |
+
#: classes/class.timeline-express.php:1351
|
186 |
+
msgid "Support"
|
187 |
+
msgstr "Supporto"
|
188 |
+
|
189 |
+
#: lib/about-metabox-template.php:38
|
190 |
+
msgid "Help!"
|
191 |
+
msgstr "Aiuto!"
|
192 |
+
|
193 |
+
#: lib/about-metabox-template.php:39
|
194 |
+
msgid "Review"
|
195 |
+
msgstr "Recensioni"
|
196 |
+
|
197 |
+
#: lib/about-metabox-template.php:40
|
198 |
+
msgid "Donate"
|
199 |
+
msgstr "Donazioni"
|
200 |
+
|
201 |
+
#: lib/about-metabox-template.php:50
|
202 |
+
msgid "this plugin was made with "
|
203 |
+
msgstr "Questo plugin è stato fatto con"
|
204 |
+
|
205 |
+
#: lib/about-metabox-template.php:50 pages/welcome.php:98
|
206 |
+
msgid "by"
|
207 |
+
msgstr "da"
|
208 |
+
|
209 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_ajax.php:47
|
210 |
+
msgid "Please Try Again"
|
211 |
+
msgstr "Prova di nuovo, per favore"
|
212 |
+
|
213 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_ajax.php:131
|
214 |
+
msgid "Remove Embed"
|
215 |
+
msgstr "Rimuovi l'integrazione"
|
216 |
+
|
217 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_ajax.php:134
|
218 |
+
msgid "No oEmbed Results Found for %s. View more info at"
|
219 |
+
msgstr "Nessun risultato trovato per %. Leggi altre informazioni su"
|
220 |
+
|
221 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_field.php:459
|
222 |
+
msgid "Add Group"
|
223 |
+
msgstr "Aggiungi gruppo"
|
224 |
+
|
225 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_field.php:460
|
226 |
+
msgid "Remove Group"
|
227 |
+
msgstr "Rimuovi gruppo"
|
228 |
+
|
229 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:250
|
230 |
+
msgid "Add Row"
|
231 |
+
msgstr "Aggiungi una riga"
|
232 |
+
|
233 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:306
|
234 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:706
|
235 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:768
|
236 |
+
msgid "Remove"
|
237 |
+
msgstr "Rimuovi"
|
238 |
+
|
239 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:601
|
240 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:635
|
241 |
+
msgid "No terms"
|
242 |
+
msgstr "Nessun termine"
|
243 |
+
|
244 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:674
|
245 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:728
|
246 |
+
msgid "Add or Upload File"
|
247 |
+
msgstr "Aggiungi o carica un file"
|
248 |
+
|
249 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:695
|
250 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:760
|
251 |
+
msgid "Remove Image"
|
252 |
+
msgstr "Rimuovi l'immagine"
|
253 |
+
|
254 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:706
|
255 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:768
|
256 |
+
msgid "File:"
|
257 |
+
msgstr "File:"
|
258 |
+
|
259 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:706
|
260 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:768
|
261 |
+
msgid "Download"
|
262 |
+
msgstr "Scarica"
|
263 |
+
|
264 |
+
#: lib/cmb_metaboxes/init.php:258
|
265 |
+
msgid "Clear"
|
266 |
+
msgstr "Cancella"
|
267 |
+
|
268 |
+
#: lib/cmb_metaboxes/init.php:259
|
269 |
+
msgid "Default"
|
270 |
+
msgstr "Predefinito"
|
271 |
+
|
272 |
+
#: lib/cmb_metaboxes/init.php:260
|
273 |
+
msgid "Select Color"
|
274 |
+
msgstr "Scegli il colore"
|
275 |
+
|
276 |
+
#: lib/cmb_metaboxes/init.php:261
|
277 |
+
msgid "Current Color"
|
278 |
+
msgstr "Colore attuale"
|
279 |
+
|
280 |
+
#: lib/cmb_metaboxes/init.php:288
|
281 |
+
msgid "Select / Deselect All"
|
282 |
+
msgstr "Seleziona / Deseleziona tutto"
|
283 |
+
|
284 |
+
#: lib/cmb_metaboxes/init.php:1177
|
285 |
+
msgid "Save"
|
286 |
+
msgstr "Salva"
|
287 |
+
|
288 |
+
#: lib/support-contact-form.php:9
|
289 |
+
msgid ""
|
290 |
+
"If you need support, please fill out the following form. I will get back to you "
|
291 |
+
"with some support as soon as possible."
|
292 |
+
msgstr ""
|
293 |
+
"Se avete bisogno di aiuto, compilate il form sottostante. Cercherò di "
|
294 |
+
"rispondervi non appena possibile"
|
295 |
+
|
296 |
+
#: lib/support-contact-form.php:10
|
297 |
+
msgid "note: support requests are limitd to one per hour, to help reduce spam."
|
298 |
+
msgstr ""
|
299 |
+
"nota: le richieste di aiuto sono limitate a una all'ora, per aiutare a ridurre "
|
300 |
+
"lo spai."
|
301 |
+
|
302 |
+
#: lib/support-contact-form.php:13
|
303 |
+
msgid "Your name"
|
304 |
+
msgstr "Nome"
|
305 |
+
|
306 |
+
#: lib/support-contact-form.php:15
|
307 |
+
msgid "Your message"
|
308 |
+
msgstr "Messaggio"
|
309 |
+
|
310 |
+
#: lib/support-contact-form.php:16
|
311 |
+
msgid "please describe your issue in as much detail as possible"
|
312 |
+
msgstr "descrivete il problema nel modo più dettagliato possibile, per favore"
|
313 |
+
|
314 |
+
#: lib/support-contact-form.php:37
|
315 |
+
msgid "There was an error sending your request"
|
316 |
+
msgstr "C'è stato un errore nella trasmissione del messaggio"
|
317 |
+
|
318 |
+
#: lib/support-contact-form.php:38
|
319 |
+
msgid "If the error persists, please contact me directly for support at"
|
320 |
+
msgstr "Se l'errore persiste, contattatemi direttamente a questo indirizzo"
|
321 |
+
|
322 |
+
#: lib/support-contact-form.php:42
|
323 |
+
msgid ""
|
324 |
+
"Support request successfully sent. I will be in touch regarding your issue "
|
325 |
+
"shortly."
|
326 |
+
msgstr ""
|
327 |
+
"Richiesta di aiuto inviata con successo. Vi risponderò non appena possibile."
|
328 |
+
|
329 |
+
#: pages/options.php:27
|
330 |
+
msgid "The options were saved successfully!"
|
331 |
+
msgstr "Le opzioni sono state salvate con successo!"
|
332 |
+
|
333 |
+
#: pages/options.php:30
|
334 |
+
msgid "The options could not be saved (or you did not change them)."
|
335 |
+
msgstr ""
|
336 |
+
"Non è stato possibile salvare le opzioni (o forse non avevi cambiato nulla)"
|
337 |
+
|
338 |
+
#: pages/options.php:45
|
339 |
+
msgid ""
|
340 |
+
"Are you sure you want to revert 'Timeline Express' settings? This cannot be "
|
341 |
+
"undone."
|
342 |
+
msgstr ""
|
343 |
+
"Sei sicuro di voler risettare le impostazioni di \"Timeline Express\"? E' "
|
344 |
+
"un'azione irreversibile."
|
345 |
+
|
346 |
+
#: pages/options.php:58
|
347 |
+
msgid "Timeline Express settings have successfully been reset"
|
348 |
+
msgstr "I parametri di Timeline Express sono stati reinizializzati con successo."
|
349 |
+
|
350 |
+
#: pages/options.php:141
|
351 |
+
msgid "Please Consider"
|
352 |
+
msgstr "Grazie!"
|
353 |
+
|
354 |
+
#: pages/options.php:142
|
355 |
+
msgid "Making a Donation"
|
356 |
+
msgstr "Fai una donazione"
|
357 |
+
|
358 |
+
#: pages/options.php:150
|
359 |
+
msgid "Need Help?"
|
360 |
+
msgstr "Bisogno di aiuto?"
|
361 |
+
|
362 |
+
#: pages/options.php:151
|
363 |
+
msgid "Get Support Now!"
|
364 |
+
msgstr "Ottieni aiuto!"
|
365 |
+
|
366 |
+
#: pages/options.php:159
|
367 |
+
msgid "Loving the plugin?"
|
368 |
+
msgstr "Ti piace questo plugin?"
|
369 |
+
|
370 |
+
#: pages/options.php:160
|
371 |
+
msgid "Leave us a nice review"
|
372 |
+
msgstr "Scrivici una bella recensione!"
|
373 |
+
|
374 |
+
# not sure
|
375 |
+
#: pages/options.php:172
|
376 |
+
msgid ""
|
377 |
+
"make adjustments to your timeline here, ranging from style to display options"
|
378 |
+
msgstr ""
|
379 |
+
"Qui puoi modificare la tua timeline, dallo stile alle opzioni di "
|
380 |
+
"visualizzazione "
|
381 |
+
|
382 |
+
#: pages/options.php:185
|
383 |
+
msgid "Timeline Title"
|
384 |
+
msgstr "Titolo della timeline"
|
385 |
+
|
386 |
+
#: pages/options.php:189
|
387 |
+
msgid "Left"
|
388 |
+
msgstr "Sinistra"
|
389 |
+
|
390 |
+
#: pages/options.php:190
|
391 |
+
msgid "Center"
|
392 |
+
msgstr "Centro"
|
393 |
+
|
394 |
+
#: pages/options.php:191
|
395 |
+
msgid "Right"
|
396 |
+
msgstr "Destra"
|
397 |
+
|
398 |
+
#: pages/options.php:194
|
399 |
+
msgid "H1"
|
400 |
+
msgstr "H1"
|
401 |
+
|
402 |
+
#: pages/options.php:195
|
403 |
+
msgid "H2"
|
404 |
+
msgstr "H2"
|
405 |
+
|
406 |
+
#: pages/options.php:196
|
407 |
+
msgid "H3"
|
408 |
+
msgstr "H3"
|
409 |
+
|
410 |
+
#: pages/options.php:197
|
411 |
+
msgid "H4"
|
412 |
+
msgstr "H4"
|
413 |
+
|
414 |
+
#: pages/options.php:205
|
415 |
+
msgid ""
|
416 |
+
"Enter the title for the time line // Select the alignment // Select the font "
|
417 |
+
"size"
|
418 |
+
msgstr ""
|
419 |
+
"Inserisci il titolo della timeline // Scegli l'allineamento // Scegli le "
|
420 |
+
"dimensioni del font"
|
421 |
+
|
422 |
+
#: pages/options.php:210
|
423 |
+
msgid "Time Frame"
|
424 |
+
msgstr "Intervallo temporale"
|
425 |
+
|
426 |
+
#: pages/options.php:213
|
427 |
+
msgid "Future Events"
|
428 |
+
msgstr "Eventi futuri"
|
429 |
+
|
430 |
+
#: pages/options.php:214
|
431 |
+
msgid "All Events (past+future)"
|
432 |
+
msgstr "Tutti gli eventi (passati e futuri)"
|
433 |
+
|
434 |
+
#: pages/options.php:215
|
435 |
+
msgid "Past Events"
|
436 |
+
msgstr "Eventi passati"
|
437 |
+
|
438 |
+
#: pages/options.php:223
|
439 |
+
msgid "Select the time frame to query events from."
|
440 |
+
msgstr "Seleziona l'intervallo temporale degli eventi"
|
441 |
+
|
442 |
+
#: pages/options.php:228
|
443 |
+
msgid "Display Order"
|
444 |
+
msgstr "Ordine di comparsa"
|
445 |
+
|
446 |
+
#: pages/options.php:231
|
447 |
+
msgid "Ascending"
|
448 |
+
msgstr "Ascendente"
|
449 |
+
|
450 |
+
#: pages/options.php:232
|
451 |
+
msgid "Descending"
|
452 |
+
msgstr "Discendente"
|
453 |
+
|
454 |
+
#: pages/options.php:240
|
455 |
+
msgid ""
|
456 |
+
"Select the order you would like the announcements to display. Ascending : "
|
457 |
+
"Chronological order by announcement date. Descending : Reverse chronological "
|
458 |
+
"order by announcement date."
|
459 |
+
msgstr ""
|
460 |
+
"Seleziona l'ordine in cui vuoi che compaiano gli annunci. Ascendente: dal meno "
|
461 |
+
"recente al più recente. Discendente: dal più recente al meno recente."
|
462 |
+
|
463 |
+
#: pages/options.php:245
|
464 |
+
msgid "Announcement Excerpt Length"
|
465 |
+
msgstr "Lunghezza del riassunto dell'annuncio"
|
466 |
+
|
467 |
+
#: pages/options.php:254
|
468 |
+
msgid ""
|
469 |
+
"Set the length of the excerpt for each announcement. ( min=25;max=500 eg: 50 = "
|
470 |
+
"50 characters )"
|
471 |
+
msgstr ""
|
472 |
+
"Regola la lunghezza del riassunto di ciascun annuncio. (Min = 25; max = 500; "
|
473 |
+
"esempio: 50 = 50 caratteri)"
|
474 |
+
|
475 |
+
#: pages/options.php:259
|
476 |
+
msgid "Date Visibility"
|
477 |
+
msgstr "Visibilità della data"
|
478 |
+
|
479 |
+
#: pages/options.php:262 pages/options.php:279
|
480 |
+
msgid "Visible"
|
481 |
+
msgstr "Visibile"
|
482 |
+
|
483 |
+
#: pages/options.php:263 pages/options.php:280
|
484 |
+
msgid "Hidden"
|
485 |
+
msgstr "Invisibile"
|
486 |
+
|
487 |
+
#: pages/options.php:271
|
488 |
+
msgid "Toggle the visibility of the date next to the icon."
|
489 |
+
msgstr "Scegli la visibilità della data a fianco dell'icona"
|
490 |
+
|
491 |
+
#: pages/options.php:276
|
492 |
+
msgid "Read More Visibility"
|
493 |
+
msgstr "Visibilità di \"Leggi oltre\""
|
494 |
+
|
495 |
+
#: pages/options.php:288
|
496 |
+
msgid ""
|
497 |
+
"Toggle the visibility of the read more button. Hide to prevent users from "
|
498 |
+
"viewing the full announcement."
|
499 |
+
msgstr ""
|
500 |
+
"Scegli la visibilità del bottone \"Leggi oltre\". Nascondi per impedire ai "
|
501 |
+
"lettori di visualizzare l'annuncio intero."
|
502 |
+
|
503 |
+
#: pages/options.php:293
|
504 |
+
msgid "Default Icon"
|
505 |
+
msgstr "Icona predefinita"
|
506 |
+
|
507 |
+
#: pages/options.php:305
|
508 |
+
msgid ""
|
509 |
+
"Select the font-awesome class name that you would like to use a default icon "
|
510 |
+
"for new events in the dropdown above."
|
511 |
+
msgstr ""
|
512 |
+
"Seleziona l'icona che vorresti usare come icona predefinita dal menu a tendina."
|
513 |
+
|
514 |
+
#: pages/options.php:310
|
515 |
+
msgid "Default Announcement Color"
|
516 |
+
msgstr "Colore predefinito dell'annuncio"
|
517 |
+
|
518 |
+
#: pages/options.php:319
|
519 |
+
msgid ""
|
520 |
+
"Select the default color for all new events. Note : this setting can be "
|
521 |
+
"overwritten"
|
522 |
+
msgstr ""
|
523 |
+
"Seleziona il colore predefinito di tutti i nuovi eventi. Nota: questa "
|
524 |
+
"impostazione può essere sovrascritta"
|
525 |
+
|
526 |
+
#: pages/options.php:324
|
527 |
+
msgid "Announcement Container Background"
|
528 |
+
msgstr "Colore di sfondo dell'annuncio"
|
529 |
+
|
530 |
+
#: pages/options.php:333
|
531 |
+
msgid "Select the background color of the announcement container."
|
532 |
+
msgstr "Seleziona il colore di sfondo dell'annuncio"
|
533 |
+
|
534 |
+
#: pages/options.php:338
|
535 |
+
msgid "Announcement Shadow Color"
|
536 |
+
msgstr "Colore dell'ombreggiatura dell'annuncio"
|
537 |
+
|
538 |
+
#: pages/options.php:347
|
539 |
+
msgid "Select the shadow color for the announcement container."
|
540 |
+
msgstr "Seleziona il colore dell'ombreggiatura dell'annuncio"
|
541 |
+
|
542 |
+
#: pages/options.php:352
|
543 |
+
msgid "Background Line Color"
|
544 |
+
msgstr "Colore di sfondo della timeline"
|
545 |
+
|
546 |
+
#: pages/options.php:361
|
547 |
+
msgid "Select the color of the line in the background of the timeline."
|
548 |
+
msgstr "Seleziona il colore dello sfondo della timeline"
|
549 |
+
|
550 |
+
#: pages/options.php:366
|
551 |
+
msgid "No Announcements Message"
|
552 |
+
msgstr "Messaggio in caso di nessun annuncio trovato"
|
553 |
+
|
554 |
+
#: pages/options.php:375
|
555 |
+
msgid "This is the message that will display when no announcements are found."
|
556 |
+
msgstr ""
|
557 |
+
"Questo è il messaggio che sarà mostrato quando non si trova nessun annuncio"
|
558 |
+
|
559 |
+
#: pages/options.php:380
|
560 |
+
msgid "Exclude Announcements from Site Searches"
|
561 |
+
msgstr "Escludere gli annunci dalle ricerche"
|
562 |
+
|
563 |
+
#: pages/options.php:383
|
564 |
+
msgid "True"
|
565 |
+
msgstr "Vero"
|
566 |
+
|
567 |
+
#: pages/options.php:384
|
568 |
+
msgid "False"
|
569 |
+
msgstr "Falso"
|
570 |
+
|
571 |
+
#: pages/options.php:392
|
572 |
+
msgid ""
|
573 |
+
"Set to true to exclude announcements from all site searches. False will include "
|
574 |
+
"announcements in site searches."
|
575 |
+
msgstr ""
|
576 |
+
"Vero: esclude gli annunci dai motori di ricerca. Falso: include gli annunci "
|
577 |
+
"nelle ricerche."
|
578 |
+
|
579 |
+
#: pages/options.php:397
|
580 |
+
msgid "Delete Announcements On Uninstall?"
|
581 |
+
msgstr "Cancellare gli annunci durante la disinstallazione?"
|
582 |
+
|
583 |
+
#: pages/options.php:406
|
584 |
+
msgid ""
|
585 |
+
"Select this to delete all announcement posts from the data base on plugin "
|
586 |
+
"uninstallation. this can not be undone, once they are deleted they are gone "
|
587 |
+
"forever. If you want to keep them, export your announcements before "
|
588 |
+
"uninstalling."
|
589 |
+
msgstr ""
|
590 |
+
"Selezionare questa opzione per cancellare tutti gli annunci durante la "
|
591 |
+
"disinstallazione del plugin. Questa azione non può essere annullata: una volta "
|
592 |
+
"cancellati, saranno scomparsi per sempre. Se volete conservarli, esportateli "
|
593 |
+
"prima di disinstallare il plugin."
|
594 |
+
|
595 |
+
#: pages/options.php:411
|
596 |
+
msgid "Save Settings"
|
597 |
+
msgstr "Salva le impostazioni"
|
598 |
+
|
599 |
+
#: pages/options.php:411
|
600 |
+
msgid "Reset Plugin Settings"
|
601 |
+
msgstr "Resetta impostazioni"
|
602 |
+
|
603 |
+
#: pages/support.php:26
|
604 |
+
msgid "Timeline Express Support"
|
605 |
+
msgstr "Aiuto Timeline Express"
|
606 |
+
|
607 |
+
#: pages/support.php:29
|
608 |
+
msgid "Thank you for purchasing a support license!"
|
609 |
+
msgstr "Grazie per aver acquistato una licenza!"
|
610 |
+
|
611 |
+
#: pages/support.php:30
|
612 |
+
msgid ""
|
613 |
+
"If you run into any issues, or need support, feel free to submit a support "
|
614 |
+
"ticket via the contact form below."
|
615 |
+
msgstr ""
|
616 |
+
"Se avete dei problemi o avete bisogno di aiuto, non esitate ad aprire un ticket "
|
617 |
+
"tramite il form"
|
618 |
+
|
619 |
+
#: pages/support.php:33
|
620 |
+
msgid "Have a support request? Please consider "
|
621 |
+
msgstr "Avete bisogno di aiuto? Prendete in considerazione"
|
622 |
+
|
623 |
+
#: pages/support.php:34
|
624 |
+
msgid "purchasing "
|
625 |
+
msgstr "di acquistare"
|
626 |
+
|
627 |
+
#: pages/support.php:35
|
628 |
+
msgid "a support license."
|
629 |
+
msgstr "una licenza di aiuto."
|
630 |
+
|
631 |
+
#: pages/support.php:37
|
632 |
+
msgid ""
|
633 |
+
"Your purchase will go towards the continued development and support of Timeline "
|
634 |
+
"Express, so the plugin will continue to thrive and improve."
|
635 |
+
msgstr ""
|
636 |
+
"Il vostro acquisto aiuterà a sviluppare e mantenere Timeline Express, così che "
|
637 |
+
"il plugin potrà continuare a vivere e migliorare."
|
638 |
+
|
639 |
+
#: pages/support.php:73
|
640 |
+
msgid "Support License Key"
|
641 |
+
msgstr "Chiave della licenza di aiuto"
|
642 |
+
|
643 |
+
#: pages/support.php:77
|
644 |
+
msgid "Support license key"
|
645 |
+
msgstr "Chiave della licenza di aiuto"
|
646 |
+
|
647 |
+
#: pages/support.php:80
|
648 |
+
msgid "Valid and Active License"
|
649 |
+
msgstr "Valida e attiva la licenza"
|
650 |
+
|
651 |
+
#: pages/support.php:83 pages/support.php:88 pages/support.php:98
|
652 |
+
msgid "Purchase a License"
|
653 |
+
msgstr "Acquista una licenza"
|
654 |
+
|
655 |
+
#: pages/support.php:85
|
656 |
+
msgid ""
|
657 |
+
"There was an error with your license. It appears that your license key has been "
|
658 |
+
msgstr "C'è stato un errore. Sembra che la vostra licenza"
|
659 |
+
|
660 |
+
#: pages/support.php:85
|
661 |
+
msgid "Please get in contact with support at "
|
662 |
+
msgstr "Mettiti in contatto con noi "
|
663 |
+
|
664 |
+
#: pages/support.php:85
|
665 |
+
msgid "EH Dev. Shop"
|
666 |
+
msgstr "EH Dev. Shop"
|
667 |
+
|
668 |
+
#: pages/support.php:85
|
669 |
+
msgid " to resolve the issue"
|
670 |
+
msgstr "per risolvere il problema"
|
671 |
+
|
672 |
+
#: pages/support.php:90
|
673 |
+
msgid ""
|
674 |
+
"Sorry this license key appears to be invalid. Please purchase a valid license "
|
675 |
+
"key."
|
676 |
+
msgstr "Sembra che questa chiave non sia valida. Acquista una chiave valida!"
|
677 |
+
|
678 |
+
#: pages/support.php:92
|
679 |
+
msgid "Renew your Timeline Express license"
|
680 |
+
msgstr "Rinnova la licenza Timeline Express"
|
681 |
+
|
682 |
+
#: pages/support.php:93
|
683 |
+
msgid "Renew Your License"
|
684 |
+
msgstr "Rinnova la licenza"
|
685 |
+
|
686 |
+
#: pages/support.php:95
|
687 |
+
msgid ""
|
688 |
+
"Oops, it looks like your license has expired. Please consider renewing your "
|
689 |
+
"license for another year to continue receiving support."
|
690 |
+
msgstr ""
|
691 |
+
"Ops, sembra che la licenza sia scaduta. Valuta se rinnovarla per un altro anno "
|
692 |
+
"in modo da continuare a ricevere il nostro aiuto."
|
693 |
+
|
694 |
+
#: pages/support.php:116
|
695 |
+
msgid "Deactivate License"
|
696 |
+
msgstr "Disattiva la licenza"
|
697 |
+
|
698 |
+
#: pages/support.php:120
|
699 |
+
msgid "Activate License"
|
700 |
+
msgstr "Attiva la licenza"
|
701 |
+
|
702 |
+
#: pages/support.php:141
|
703 |
+
msgid "License Info."
|
704 |
+
msgstr "Info della licenza"
|
705 |
+
|
706 |
+
#: pages/support.php:149
|
707 |
+
msgid "License Holder"
|
708 |
+
msgstr "Titolare della licenza"
|
709 |
+
|
710 |
+
#: pages/support.php:154
|
711 |
+
msgid "Sites Active/Limit"
|
712 |
+
msgstr "Siti attivi / limite"
|
713 |
+
|
714 |
+
#: pages/support.php:159
|
715 |
+
msgid "License Expires"
|
716 |
+
msgstr "La licenza scade"
|
717 |
+
|
718 |
+
#: pages/support.php:168
|
719 |
+
msgid "Premium Support Ticketing"
|
720 |
+
msgstr "Apri un ticket premium"
|
721 |
+
|
722 |
+
#: pages/support.php:174
|
723 |
+
msgid ""
|
724 |
+
"It looks like you have recently sent us a support request. We limit the number "
|
725 |
+
"of support requests to 1 per hour, to avoid spam. Sorry for the inconvinience, "
|
726 |
+
"and thank you for understanding."
|
727 |
+
msgstr ""
|
728 |
+
"Sembra che tu abbia già inviato una richiesta di aiuto. Le limitiamo a 1 "
|
729 |
+
"all'ora per evitare lo spai. Ci spiace per l'inconveniente!"
|
730 |
+
|
731 |
+
#: pages/welcome.php:42
|
732 |
+
msgid "Welcome to Timeline Express"
|
733 |
+
msgstr "Benvenuto a Timeline Express"
|
734 |
+
|
735 |
+
#: pages/welcome.php:45
|
736 |
+
msgid ""
|
737 |
+
"Thanks for installing Timeline Express. We know you're going to find this free "
|
738 |
+
"plugin super helpful and easy to use! To get started, hover over 'Timeline "
|
739 |
+
"Express', in the admin menu, and click"
|
740 |
+
msgstr ""
|
741 |
+
"Grazie di aver installato Timeline Express. Sappiamo che questo plugin ti sarà "
|
742 |
+
"utilissimo e sarà facile da usare! Per iniziare, passa il mouse sopra "
|
743 |
+
"\"Timeline Express\" nel menu e clicca"
|
744 |
+
|
745 |
+
#: pages/welcome.php:45
|
746 |
+
msgid "'New Announcement'"
|
747 |
+
msgstr "'\"Nuovo annuncio\""
|
748 |
+
|
749 |
+
#: pages/welcome.php:45
|
750 |
+
msgid " to start adding announcements your timeline!"
|
751 |
+
msgstr "per aggiungere un annuncio alla tua timeline!"
|
752 |
+
|
753 |
+
#: pages/welcome.php:47
|
754 |
+
msgid "or head over to the"
|
755 |
+
msgstr "oppure passa a"
|
756 |
+
|
757 |
+
#: pages/welcome.php:47
|
758 |
+
msgid "Settings Page"
|
759 |
+
msgstr "Impostazioni"
|
760 |
+
|
761 |
+
#: pages/welcome.php:47
|
762 |
+
msgid "to customize and style your form"
|
763 |
+
msgstr "per personalizzare il form"
|
764 |
+
|
765 |
+
#: pages/welcome.php:56
|
766 |
+
msgid "Create a Beautiful Timeline In Minutes"
|
767 |
+
msgstr "Crea una splendida timeline in pochi minuti"
|
768 |
+
|
769 |
+
#: pages/welcome.php:57
|
770 |
+
msgid ""
|
771 |
+
"Create a vertical and responsive, CSS3 animated timeline fast...without ever "
|
772 |
+
"writing a single line of code."
|
773 |
+
msgstr ""
|
774 |
+
"Crea una timeline verticale, responsive e animata, CSS3… senza dover scrivere "
|
775 |
+
"una singola riga di codice."
|
776 |
+
|
777 |
+
#: pages/welcome.php:60
|
778 |
+
msgid "Font Awesome Included"
|
779 |
+
msgstr "Include i Font Awesome"
|
780 |
+
|
781 |
+
#: pages/welcome.php:61
|
782 |
+
msgid ""
|
783 |
+
"Hundreds of icons to choose from to make your announcements really stand out!"
|
784 |
+
msgstr ""
|
785 |
+
"Centinaia di icone tra cui scegliere per valorizzare al massimo i vostri "
|
786 |
+
"annunci!"
|
787 |
+
|
788 |
+
#: pages/welcome.php:70
|
789 |
+
msgid "Intuitive Custom Post Creation Screen"
|
790 |
+
msgstr "Creazione dei custom post intuitiva"
|
791 |
+
|
792 |
+
#: pages/welcome.php:74
|
793 |
+
msgid "Manage Announcements Easily"
|
794 |
+
msgstr "Gestione facile degli annunci"
|
795 |
+
|
796 |
+
#: pages/welcome.php:78
|
797 |
+
msgid "Style The Timeline"
|
798 |
+
msgstr "Personalizza lo stile della timeline"
|
799 |
+
|
800 |
+
#: pages/welcome.php:86
|
801 |
+
msgid "Timeline Express // Sample Timeline"
|
802 |
+
msgstr "Timeline Express // esempio di Timeline"
|
803 |
+
|
804 |
+
#: pages/welcome.php:98
|
805 |
+
msgid "this free plugin was made with"
|
806 |
+
msgstr "questo plugin gratuito è stato realizzato con"
|
807 |
+
|
808 |
+
#: pages/welcome.php:98
|
809 |
+
msgid "Please consider making a"
|
810 |
+
msgstr "Considera di fare una"
|
811 |
+
|
812 |
+
#: pages/welcome.php:98
|
813 |
+
msgid "donation"
|
814 |
+
msgstr "donazione"
|
815 |
+
|
816 |
+
#: pages/welcome.php:98
|
817 |
+
msgid "if you need support in any way."
|
818 |
+
msgstr "se hai bisogno di aiuto. Grazie!"
|
819 |
+
|
820 |
+
#: pages/welcome.php:102
|
821 |
+
msgid "Keep Up With Me Elsewhere "
|
822 |
+
msgstr "Trovami anche"
|
823 |
+
|
824 |
+
#. Plugin URI of the plugin/theme
|
825 |
+
#. Author URI of the plugin/theme
|
826 |
+
msgid "http://www.evan-herman.com"
|
827 |
+
msgstr "http://www.evan-herman.com"
|
828 |
+
|
829 |
+
#. Description of the plugin/theme
|
830 |
+
msgid ""
|
831 |
+
"Create a beautiful vertical, CSS3 animated and responsive timeline in minutes "
|
832 |
+
"flat without writing code."
|
833 |
+
msgstr ""
|
834 |
+
"Crea una splendida timeline verticale, animata e responsive in pochi minuti, "
|
835 |
+
"senza scrivere una riga di codice."
|
836 |
+
|
837 |
+
#. Author of the plugin/theme
|
838 |
+
msgid "Evan Herman"
|
839 |
+
msgstr "Evan Herman"
|
languages/timeline-express.pot
ADDED
@@ -0,0 +1,796 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright (C) 2015 Timeline Express
|
2 |
+
# This file is distributed under the same license as the Timeline Express package.
|
3 |
+
msgid ""
|
4 |
+
msgstr ""
|
5 |
+
"Project-Id-Version: Timeline Express 1.1.6.6\n"
|
6 |
+
"Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/timeline-express\n"
|
7 |
+
"POT-Creation-Date: 2015-05-04 14:15:04+00:00\n"
|
8 |
+
"MIME-Version: 1.0\n"
|
9 |
+
"Content-Type: text/plain; charset=UTF-8\n"
|
10 |
+
"Content-Transfer-Encoding: 8bit\n"
|
11 |
+
"PO-Revision-Date: 2015-MO-DA HO:MI+ZONE\n"
|
12 |
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
13 |
+
"Language-Team: LANGUAGE <LL@li.org>\n"
|
14 |
+
|
15 |
+
#: classes/class.timeline-express.php:436
|
16 |
+
msgid "Timeline Express Announcements"
|
17 |
+
msgstr ""
|
18 |
+
|
19 |
+
#: classes/class.timeline-express.php:437
|
20 |
+
msgid "Announcement"
|
21 |
+
msgstr ""
|
22 |
+
|
23 |
+
#. #-#-#-#-# plugin.pot (Timeline Express 1.1.6.6) #-#-#-#-#
|
24 |
+
#. Plugin Name of the plugin/theme
|
25 |
+
#: classes/class.timeline-express.php:438
|
26 |
+
msgid "Timeline Express"
|
27 |
+
msgstr ""
|
28 |
+
|
29 |
+
#: classes/class.timeline-express.php:439
|
30 |
+
msgid "Timeline Express:"
|
31 |
+
msgstr ""
|
32 |
+
|
33 |
+
#: classes/class.timeline-express.php:440
|
34 |
+
msgid "All Announcements"
|
35 |
+
msgstr ""
|
36 |
+
|
37 |
+
#: classes/class.timeline-express.php:441
|
38 |
+
msgid "View Announcement"
|
39 |
+
msgstr ""
|
40 |
+
|
41 |
+
#: classes/class.timeline-express.php:442
|
42 |
+
#: classes/class.timeline-express.php:443
|
43 |
+
msgid "New Announcement"
|
44 |
+
msgstr ""
|
45 |
+
|
46 |
+
#: classes/class.timeline-express.php:444
|
47 |
+
msgid "Edit Announcement"
|
48 |
+
msgstr ""
|
49 |
+
|
50 |
+
#: classes/class.timeline-express.php:445
|
51 |
+
msgid "Update Announcement"
|
52 |
+
msgstr ""
|
53 |
+
|
54 |
+
#: classes/class.timeline-express.php:446
|
55 |
+
msgid "Search Announcements"
|
56 |
+
msgstr ""
|
57 |
+
|
58 |
+
#: classes/class.timeline-express.php:447
|
59 |
+
msgid "No Timeline Express Announcements Found"
|
60 |
+
msgstr ""
|
61 |
+
|
62 |
+
#: classes/class.timeline-express.php:448
|
63 |
+
msgid "No Timeline Express Announcements in Trash"
|
64 |
+
msgstr ""
|
65 |
+
|
66 |
+
#: classes/class.timeline-express.php:458
|
67 |
+
msgid "Post type for adding timeline express announcements to the site"
|
68 |
+
msgstr ""
|
69 |
+
|
70 |
+
#: classes/class.timeline-express.php:508
|
71 |
+
msgid "Announcement Color"
|
72 |
+
msgstr ""
|
73 |
+
|
74 |
+
#: classes/class.timeline-express.php:509
|
75 |
+
msgid "select the color for this announcement."
|
76 |
+
msgstr ""
|
77 |
+
|
78 |
+
#: classes/class.timeline-express.php:517
|
79 |
+
msgid "Announcement Icon"
|
80 |
+
msgstr ""
|
81 |
+
|
82 |
+
#: classes/class.timeline-express.php:518
|
83 |
+
msgid ""
|
84 |
+
"select an icon from the drop down above. This is used for the icon "
|
85 |
+
"associated with the announcement."
|
86 |
+
msgstr ""
|
87 |
+
|
88 |
+
#: classes/class.timeline-express.php:526
|
89 |
+
#: classes/class.timeline-express.php:821
|
90 |
+
#: classes/class.timeline-express.php:828
|
91 |
+
msgid "Announcement Date"
|
92 |
+
msgstr ""
|
93 |
+
|
94 |
+
#: classes/class.timeline-express.php:527
|
95 |
+
msgid ""
|
96 |
+
"enter the date of the announcement. the announcements will appear in "
|
97 |
+
"chronological order according to this date. "
|
98 |
+
msgstr ""
|
99 |
+
|
100 |
+
#: classes/class.timeline-express.php:535
|
101 |
+
msgid "Announcement Image"
|
102 |
+
msgstr ""
|
103 |
+
|
104 |
+
#: classes/class.timeline-express.php:536
|
105 |
+
msgid ""
|
106 |
+
"select a banner image for this announcement (optional). (recommended 650px "
|
107 |
+
"wide or larger) "
|
108 |
+
msgstr ""
|
109 |
+
|
110 |
+
#: classes/class.timeline-express.php:560
|
111 |
+
msgid "Announcement Info."
|
112 |
+
msgstr ""
|
113 |
+
|
114 |
+
#: classes/class.timeline-express.php:571
|
115 |
+
msgid "About"
|
116 |
+
msgstr ""
|
117 |
+
|
118 |
+
#: classes/class.timeline-express.php:598
|
119 |
+
msgid "Enter Announcement Title"
|
120 |
+
msgstr ""
|
121 |
+
|
122 |
+
#: classes/class.timeline-express.php:606
|
123 |
+
msgctxt "timeline-express"
|
124 |
+
msgid "Announcement Name"
|
125 |
+
msgstr ""
|
126 |
+
|
127 |
+
#: classes/class.timeline-express.php:607
|
128 |
+
msgctxt "timeline-express"
|
129 |
+
msgid "Color"
|
130 |
+
msgstr ""
|
131 |
+
|
132 |
+
#: classes/class.timeline-express.php:608
|
133 |
+
msgctxt "timeline-express"
|
134 |
+
msgid "Icon"
|
135 |
+
msgstr ""
|
136 |
+
|
137 |
+
#: classes/class.timeline-express.php:609
|
138 |
+
msgctxt "timeline-express"
|
139 |
+
msgid "Announcement Date"
|
140 |
+
msgstr ""
|
141 |
+
|
142 |
+
#: classes/class.timeline-express.php:610
|
143 |
+
msgctxt "timeline-express"
|
144 |
+
msgid "Image"
|
145 |
+
msgstr ""
|
146 |
+
|
147 |
+
#: classes/class.timeline-express.php:611
|
148 |
+
msgctxt "timeline-express"
|
149 |
+
msgid "Announcement Past?"
|
150 |
+
msgstr ""
|
151 |
+
|
152 |
+
#: classes/class.timeline-express.php:824
|
153 |
+
#: classes/class.timeline-express.php:831
|
154 |
+
msgid "Back"
|
155 |
+
msgstr ""
|
156 |
+
|
157 |
+
#: classes/class.timeline-express.php:1097
|
158 |
+
#: classes/class.timeline-express.php:1104
|
159 |
+
#: classes/class.timeline-express.php:1118
|
160 |
+
msgid "..."
|
161 |
+
msgstr ""
|
162 |
+
|
163 |
+
#: classes/class.timeline-express.php:1105
|
164 |
+
#: classes/class.timeline-express.php:1119
|
165 |
+
msgid "Read more"
|
166 |
+
msgstr ""
|
167 |
+
|
168 |
+
#: classes/class.timeline-express.php:1279
|
169 |
+
msgid "Error"
|
170 |
+
msgstr ""
|
171 |
+
|
172 |
+
#: classes/class.timeline-express.php:1353 pages/options.php:171
|
173 |
+
msgid "Timeline Express Settings"
|
174 |
+
msgstr ""
|
175 |
+
|
176 |
+
#: classes/class.timeline-express.php:1353
|
177 |
+
msgid "Settings"
|
178 |
+
msgstr ""
|
179 |
+
|
180 |
+
#: classes/class.timeline-express.php:1355
|
181 |
+
msgid "Timeline Express Welcome"
|
182 |
+
msgstr ""
|
183 |
+
|
184 |
+
#: classes/class.timeline-express.php:1357
|
185 |
+
msgid "Support"
|
186 |
+
msgstr ""
|
187 |
+
|
188 |
+
#: lib/about-metabox-template.php:38
|
189 |
+
msgid "Help!"
|
190 |
+
msgstr ""
|
191 |
+
|
192 |
+
#: lib/about-metabox-template.php:39
|
193 |
+
msgid "Review"
|
194 |
+
msgstr ""
|
195 |
+
|
196 |
+
#: lib/about-metabox-template.php:40
|
197 |
+
msgid "Donate"
|
198 |
+
msgstr ""
|
199 |
+
|
200 |
+
#: lib/about-metabox-template.php:50
|
201 |
+
msgid "this plugin was made with "
|
202 |
+
msgstr ""
|
203 |
+
|
204 |
+
#: lib/about-metabox-template.php:50 pages/welcome.php:98
|
205 |
+
msgid "by"
|
206 |
+
msgstr ""
|
207 |
+
|
208 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_ajax.php:47
|
209 |
+
msgid "Please Try Again"
|
210 |
+
msgstr ""
|
211 |
+
|
212 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_ajax.php:131
|
213 |
+
msgid "Remove Embed"
|
214 |
+
msgstr ""
|
215 |
+
|
216 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_ajax.php:134
|
217 |
+
msgid "No oEmbed Results Found for %s. View more info at"
|
218 |
+
msgstr ""
|
219 |
+
|
220 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_field.php:459
|
221 |
+
msgid "Add Group"
|
222 |
+
msgstr ""
|
223 |
+
|
224 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_field.php:460
|
225 |
+
msgid "Remove Group"
|
226 |
+
msgstr ""
|
227 |
+
|
228 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:250
|
229 |
+
msgid "Add Row"
|
230 |
+
msgstr ""
|
231 |
+
|
232 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:306
|
233 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:706
|
234 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:768
|
235 |
+
msgid "Remove"
|
236 |
+
msgstr ""
|
237 |
+
|
238 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:601
|
239 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:635
|
240 |
+
msgid "No terms"
|
241 |
+
msgstr ""
|
242 |
+
|
243 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:674
|
244 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:728
|
245 |
+
msgid "Add or Upload File"
|
246 |
+
msgstr ""
|
247 |
+
|
248 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:695
|
249 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:760
|
250 |
+
msgid "Remove Image"
|
251 |
+
msgstr ""
|
252 |
+
|
253 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:706
|
254 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:768
|
255 |
+
msgid "File:"
|
256 |
+
msgstr ""
|
257 |
+
|
258 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:706
|
259 |
+
#: lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php:768
|
260 |
+
msgid "Download"
|
261 |
+
msgstr ""
|
262 |
+
|
263 |
+
#: lib/cmb_metaboxes/init.php:258
|
264 |
+
msgid "Clear"
|
265 |
+
msgstr ""
|
266 |
+
|
267 |
+
#: lib/cmb_metaboxes/init.php:259
|
268 |
+
msgid "Default"
|
269 |
+
msgstr ""
|
270 |
+
|
271 |
+
#: lib/cmb_metaboxes/init.php:260
|
272 |
+
msgid "Select Color"
|
273 |
+
msgstr ""
|
274 |
+
|
275 |
+
#: lib/cmb_metaboxes/init.php:261
|
276 |
+
msgid "Current Color"
|
277 |
+
msgstr ""
|
278 |
+
|
279 |
+
#: lib/cmb_metaboxes/init.php:288
|
280 |
+
msgid "Select / Deselect All"
|
281 |
+
msgstr ""
|
282 |
+
|
283 |
+
#: lib/cmb_metaboxes/init.php:1177
|
284 |
+
msgid "Save"
|
285 |
+
msgstr ""
|
286 |
+
|
287 |
+
#: lib/support-contact-form.php:9
|
288 |
+
msgid ""
|
289 |
+
"If you need support, please fill out the following form. I will get back to "
|
290 |
+
"you with some support as soon as possible."
|
291 |
+
msgstr ""
|
292 |
+
|
293 |
+
#: lib/support-contact-form.php:10
|
294 |
+
msgid ""
|
295 |
+
"note: support requests are limited to one per hour, to help reduce spam."
|
296 |
+
msgstr ""
|
297 |
+
|
298 |
+
#: lib/support-contact-form.php:13
|
299 |
+
msgid "Your name"
|
300 |
+
msgstr ""
|
301 |
+
|
302 |
+
#: lib/support-contact-form.php:15
|
303 |
+
msgid "Your message"
|
304 |
+
msgstr ""
|
305 |
+
|
306 |
+
#: lib/support-contact-form.php:16
|
307 |
+
msgid "please describe your issue in as much detail as possible"
|
308 |
+
msgstr ""
|
309 |
+
|
310 |
+
#: lib/support-contact-form.php:37
|
311 |
+
msgid "There was an error sending your request"
|
312 |
+
msgstr ""
|
313 |
+
|
314 |
+
#: lib/support-contact-form.php:38
|
315 |
+
msgid "If the error persists, please contact me directly for support at"
|
316 |
+
msgstr ""
|
317 |
+
|
318 |
+
#: lib/support-contact-form.php:42
|
319 |
+
msgid ""
|
320 |
+
"Support request successfully sent. I will be in touch regarding your issue "
|
321 |
+
"shortly."
|
322 |
+
msgstr ""
|
323 |
+
|
324 |
+
#: pages/options.php:27
|
325 |
+
msgid "The options were saved successfully!"
|
326 |
+
msgstr ""
|
327 |
+
|
328 |
+
#: pages/options.php:30
|
329 |
+
msgid "The options could not be saved (or you did not change them)."
|
330 |
+
msgstr ""
|
331 |
+
|
332 |
+
#: pages/options.php:45
|
333 |
+
msgid ""
|
334 |
+
"Are you sure you want to revert 'Timeline Express' settings? This cannot be "
|
335 |
+
"undone."
|
336 |
+
msgstr ""
|
337 |
+
|
338 |
+
#: pages/options.php:58
|
339 |
+
msgid "Timeline Express settings have successfully been reset"
|
340 |
+
msgstr ""
|
341 |
+
|
342 |
+
#: pages/options.php:141
|
343 |
+
msgid "Please Consider"
|
344 |
+
msgstr ""
|
345 |
+
|
346 |
+
#: pages/options.php:142
|
347 |
+
msgid "Making a Donation"
|
348 |
+
msgstr ""
|
349 |
+
|
350 |
+
#: pages/options.php:150
|
351 |
+
msgid "Need Help?"
|
352 |
+
msgstr ""
|
353 |
+
|
354 |
+
#: pages/options.php:151
|
355 |
+
msgid "Get Support Now!"
|
356 |
+
msgstr ""
|
357 |
+
|
358 |
+
#: pages/options.php:159
|
359 |
+
msgid "Loving the plugin?"
|
360 |
+
msgstr ""
|
361 |
+
|
362 |
+
#: pages/options.php:160
|
363 |
+
msgid "Leave us a nice review"
|
364 |
+
msgstr ""
|
365 |
+
|
366 |
+
#: pages/options.php:172
|
367 |
+
msgid ""
|
368 |
+
"make adjustments to your timeline here, ranging from style to display options"
|
369 |
+
msgstr ""
|
370 |
+
|
371 |
+
#: pages/options.php:185
|
372 |
+
msgid "Timeline Title"
|
373 |
+
msgstr ""
|
374 |
+
|
375 |
+
#: pages/options.php:189
|
376 |
+
msgid "Left"
|
377 |
+
msgstr ""
|
378 |
+
|
379 |
+
#: pages/options.php:190
|
380 |
+
msgid "Center"
|
381 |
+
msgstr ""
|
382 |
+
|
383 |
+
#: pages/options.php:191
|
384 |
+
msgid "Right"
|
385 |
+
msgstr ""
|
386 |
+
|
387 |
+
#: pages/options.php:194
|
388 |
+
msgid "H1"
|
389 |
+
msgstr ""
|
390 |
+
|
391 |
+
#: pages/options.php:195
|
392 |
+
msgid "H2"
|
393 |
+
msgstr ""
|
394 |
+
|
395 |
+
#: pages/options.php:196
|
396 |
+
msgid "H3"
|
397 |
+
msgstr ""
|
398 |
+
|
399 |
+
#: pages/options.php:197
|
400 |
+
msgid "H4"
|
401 |
+
msgstr ""
|
402 |
+
|
403 |
+
#: pages/options.php:205
|
404 |
+
msgid ""
|
405 |
+
"Enter the title for the time line // Select the alignment // Select the font "
|
406 |
+
"size"
|
407 |
+
msgstr ""
|
408 |
+
|
409 |
+
#: pages/options.php:210
|
410 |
+
msgid "Time Frame"
|
411 |
+
msgstr ""
|
412 |
+
|
413 |
+
#: pages/options.php:213
|
414 |
+
msgid "Future Events"
|
415 |
+
msgstr ""
|
416 |
+
|
417 |
+
#: pages/options.php:214
|
418 |
+
msgid "All Events (past+future)"
|
419 |
+
msgstr ""
|
420 |
+
|
421 |
+
#: pages/options.php:215
|
422 |
+
msgid "Past Events"
|
423 |
+
msgstr ""
|
424 |
+
|
425 |
+
#: pages/options.php:223
|
426 |
+
msgid "Select the time frame to query events from."
|
427 |
+
msgstr ""
|
428 |
+
|
429 |
+
#: pages/options.php:228
|
430 |
+
msgid "Display Order"
|
431 |
+
msgstr ""
|
432 |
+
|
433 |
+
#: pages/options.php:231
|
434 |
+
msgid "Ascending"
|
435 |
+
msgstr ""
|
436 |
+
|
437 |
+
#: pages/options.php:232
|
438 |
+
msgid "Descending"
|
439 |
+
msgstr ""
|
440 |
+
|
441 |
+
#: pages/options.php:240
|
442 |
+
msgid ""
|
443 |
+
"Select the order you would like the announcements to display. Ascending : "
|
444 |
+
"Chronological order by announcement date. Descending : Reverse chronological "
|
445 |
+
"order by announcement date."
|
446 |
+
msgstr ""
|
447 |
+
|
448 |
+
#: pages/options.php:245
|
449 |
+
msgid "Announcement Excerpt Length"
|
450 |
+
msgstr ""
|
451 |
+
|
452 |
+
#: pages/options.php:254
|
453 |
+
msgid ""
|
454 |
+
"Set the length of the excerpt for each announcement. ( min=25;max=500 eg: 50 "
|
455 |
+
"= 50 characters )"
|
456 |
+
msgstr ""
|
457 |
+
|
458 |
+
#: pages/options.php:259
|
459 |
+
msgid "Date Visibility"
|
460 |
+
msgstr ""
|
461 |
+
|
462 |
+
#: pages/options.php:262 pages/options.php:279
|
463 |
+
msgid "Visible"
|
464 |
+
msgstr ""
|
465 |
+
|
466 |
+
#: pages/options.php:263 pages/options.php:280
|
467 |
+
msgid "Hidden"
|
468 |
+
msgstr ""
|
469 |
+
|
470 |
+
#: pages/options.php:271
|
471 |
+
msgid "Toggle the visibility of the date next to the icon."
|
472 |
+
msgstr ""
|
473 |
+
|
474 |
+
#: pages/options.php:276
|
475 |
+
msgid "Read More Visibility"
|
476 |
+
msgstr ""
|
477 |
+
|
478 |
+
#: pages/options.php:288
|
479 |
+
msgid ""
|
480 |
+
"Toggle the visibility of the read more button. Hide to prevent users from "
|
481 |
+
"viewing the full announcement."
|
482 |
+
msgstr ""
|
483 |
+
|
484 |
+
#: pages/options.php:293
|
485 |
+
msgid "Default Icon"
|
486 |
+
msgstr ""
|
487 |
+
|
488 |
+
#: pages/options.php:305
|
489 |
+
msgid ""
|
490 |
+
"Select the font-awesome class name that you would like to use a default icon "
|
491 |
+
"for new events in the dropdown above."
|
492 |
+
msgstr ""
|
493 |
+
|
494 |
+
#: pages/options.php:310
|
495 |
+
msgid "Default Announcement Color"
|
496 |
+
msgstr ""
|
497 |
+
|
498 |
+
#: pages/options.php:319
|
499 |
+
msgid ""
|
500 |
+
"Select the default color for all new events. Note : this setting can be "
|
501 |
+
"overwritten"
|
502 |
+
msgstr ""
|
503 |
+
|
504 |
+
#: pages/options.php:324
|
505 |
+
msgid "Announcement Container Background"
|
506 |
+
msgstr ""
|
507 |
+
|
508 |
+
#: pages/options.php:333
|
509 |
+
msgid "Select the background color of the announcement container."
|
510 |
+
msgstr ""
|
511 |
+
|
512 |
+
#: pages/options.php:338
|
513 |
+
msgid "Announcement Shadow Color"
|
514 |
+
msgstr ""
|
515 |
+
|
516 |
+
#: pages/options.php:347
|
517 |
+
msgid "Select the shadow color for the announcement container."
|
518 |
+
msgstr ""
|
519 |
+
|
520 |
+
#: pages/options.php:352
|
521 |
+
msgid "Background Line Color"
|
522 |
+
msgstr ""
|
523 |
+
|
524 |
+
#: pages/options.php:361
|
525 |
+
msgid "Select the color of the line in the background of the timeline."
|
526 |
+
msgstr ""
|
527 |
+
|
528 |
+
#: pages/options.php:366
|
529 |
+
msgid "No Announcements Message"
|
530 |
+
msgstr ""
|
531 |
+
|
532 |
+
#: pages/options.php:375
|
533 |
+
msgid "This is the message that will display when no announcements are found."
|
534 |
+
msgstr ""
|
535 |
+
|
536 |
+
#: pages/options.php:380
|
537 |
+
msgid "Exclude Announcements from Site Searches"
|
538 |
+
msgstr ""
|
539 |
+
|
540 |
+
#: pages/options.php:383
|
541 |
+
msgid "True"
|
542 |
+
msgstr ""
|
543 |
+
|
544 |
+
#: pages/options.php:384
|
545 |
+
msgid "False"
|
546 |
+
msgstr ""
|
547 |
+
|
548 |
+
#: pages/options.php:392
|
549 |
+
msgid ""
|
550 |
+
"Set to true to exclude announcements from all site searches. False will "
|
551 |
+
"include announcements in site searches."
|
552 |
+
msgstr ""
|
553 |
+
|
554 |
+
#: pages/options.php:397
|
555 |
+
msgid "Delete Announcements On Uninstall?"
|
556 |
+
msgstr ""
|
557 |
+
|
558 |
+
#: pages/options.php:406
|
559 |
+
msgid ""
|
560 |
+
"Select this to delete all announcement posts from the data base on plugin "
|
561 |
+
"uninstallation. this can not be undone, once they are deleted they are gone "
|
562 |
+
"forever. If you want to keep them, export your announcements before "
|
563 |
+
"uninstalling."
|
564 |
+
msgstr ""
|
565 |
+
|
566 |
+
#: pages/options.php:411
|
567 |
+
msgid "Save Settings"
|
568 |
+
msgstr ""
|
569 |
+
|
570 |
+
#: pages/options.php:411
|
571 |
+
msgid "Reset Plugin Settings"
|
572 |
+
msgstr ""
|
573 |
+
|
574 |
+
#: pages/support.php:26
|
575 |
+
msgid "Timeline Express Support"
|
576 |
+
msgstr ""
|
577 |
+
|
578 |
+
#: pages/support.php:29
|
579 |
+
msgid "Thank you for purchasing a support license!"
|
580 |
+
msgstr ""
|
581 |
+
|
582 |
+
#: pages/support.php:30
|
583 |
+
msgid ""
|
584 |
+
"If you run into any issues, or need support, feel free to submit a support "
|
585 |
+
"ticket via the contact form below."
|
586 |
+
msgstr ""
|
587 |
+
|
588 |
+
#: pages/support.php:33
|
589 |
+
msgid "Have a support request? Please consider "
|
590 |
+
msgstr ""
|
591 |
+
|
592 |
+
#: pages/support.php:34
|
593 |
+
msgid "purchasing "
|
594 |
+
msgstr ""
|
595 |
+
|
596 |
+
#: pages/support.php:35
|
597 |
+
msgid "a support license."
|
598 |
+
msgstr ""
|
599 |
+
|
600 |
+
#: pages/support.php:37
|
601 |
+
msgid ""
|
602 |
+
"Your purchase will go towards the continued development and support of "
|
603 |
+
"Timeline Express, so the plugin will continue to thrive and improve."
|
604 |
+
msgstr ""
|
605 |
+
|
606 |
+
#: pages/support.php:73
|
607 |
+
msgid "Support License Key"
|
608 |
+
msgstr ""
|
609 |
+
|
610 |
+
#: pages/support.php:77
|
611 |
+
msgid "Support license key"
|
612 |
+
msgstr ""
|
613 |
+
|
614 |
+
#: pages/support.php:80
|
615 |
+
msgid "Valid and Active License"
|
616 |
+
msgstr ""
|
617 |
+
|
618 |
+
#: pages/support.php:83 pages/support.php:88 pages/support.php:98
|
619 |
+
msgid "Purchase a License"
|
620 |
+
msgstr ""
|
621 |
+
|
622 |
+
#: pages/support.php:85
|
623 |
+
msgid ""
|
624 |
+
"There was an error with your license. It appears that your license key has "
|
625 |
+
"been "
|
626 |
+
msgstr ""
|
627 |
+
|
628 |
+
#: pages/support.php:85
|
629 |
+
msgid "Please get in contact with support at "
|
630 |
+
msgstr ""
|
631 |
+
|
632 |
+
#: pages/support.php:85
|
633 |
+
msgid "EH Dev. Shop"
|
634 |
+
msgstr ""
|
635 |
+
|
636 |
+
#: pages/support.php:85
|
637 |
+
msgid " to resolve the issue"
|
638 |
+
msgstr ""
|
639 |
+
|
640 |
+
#: pages/support.php:90
|
641 |
+
msgid ""
|
642 |
+
"Sorry this license key appears to be invalid. Please purchase a valid "
|
643 |
+
"license key."
|
644 |
+
msgstr ""
|
645 |
+
|
646 |
+
#: pages/support.php:92
|
647 |
+
msgid "Renew your Timeline Express license"
|
648 |
+
msgstr ""
|
649 |
+
|
650 |
+
#: pages/support.php:93
|
651 |
+
msgid "Renew Your License"
|
652 |
+
msgstr ""
|
653 |
+
|
654 |
+
#: pages/support.php:95
|
655 |
+
msgid ""
|
656 |
+
"Oops, it looks like your license has expired. Please consider renewing your "
|
657 |
+
"license for another year to continue receiving support."
|
658 |
+
msgstr ""
|
659 |
+
|
660 |
+
#: pages/support.php:116
|
661 |
+
msgid "Deactivate License"
|
662 |
+
msgstr ""
|
663 |
+
|
664 |
+
#: pages/support.php:120
|
665 |
+
msgid "Activate License"
|
666 |
+
msgstr ""
|
667 |
+
|
668 |
+
#: pages/support.php:141
|
669 |
+
msgid "License Info."
|
670 |
+
msgstr ""
|
671 |
+
|
672 |
+
#: pages/support.php:149
|
673 |
+
msgid "License Holder"
|
674 |
+
msgstr ""
|
675 |
+
|
676 |
+
#: pages/support.php:154
|
677 |
+
msgid "Sites Active/Limit"
|
678 |
+
msgstr ""
|
679 |
+
|
680 |
+
#: pages/support.php:159
|
681 |
+
msgid "License Expires"
|
682 |
+
msgstr ""
|
683 |
+
|
684 |
+
#: pages/support.php:168
|
685 |
+
msgid "Premium Support Ticketing"
|
686 |
+
msgstr ""
|
687 |
+
|
688 |
+
#: pages/support.php:174
|
689 |
+
msgid ""
|
690 |
+
"It looks like you have recently sent us a support request. We limit the "
|
691 |
+
"number of support requests to 1 per hour, to avoid spam. Sorry for the "
|
692 |
+
"inconvinience, and thank you for understanding."
|
693 |
+
msgstr ""
|
694 |
+
|
695 |
+
#: pages/welcome.php:42
|
696 |
+
msgid "Welcome to Timeline Express"
|
697 |
+
msgstr ""
|
698 |
+
|
699 |
+
#: pages/welcome.php:45
|
700 |
+
msgid ""
|
701 |
+
"Thanks for installing Timeline Express. We know you're going to find this "
|
702 |
+
"free plugin super helpful and easy to use! To get started, hover over "
|
703 |
+
"'Timeline Express', in the admin menu, and click"
|
704 |
+
msgstr ""
|
705 |
+
|
706 |
+
#: pages/welcome.php:45
|
707 |
+
msgid "'New Announcement'"
|
708 |
+
msgstr ""
|
709 |
+
|
710 |
+
#: pages/welcome.php:45
|
711 |
+
msgid " to start adding announcements your timeline!"
|
712 |
+
msgstr ""
|
713 |
+
|
714 |
+
#: pages/welcome.php:47
|
715 |
+
msgid "or head over to the"
|
716 |
+
msgstr ""
|
717 |
+
|
718 |
+
#: pages/welcome.php:47
|
719 |
+
msgid "Settings Page"
|
720 |
+
msgstr ""
|
721 |
+
|
722 |
+
#: pages/welcome.php:47
|
723 |
+
msgid "to customize and style your form"
|
724 |
+
msgstr ""
|
725 |
+
|
726 |
+
#: pages/welcome.php:56
|
727 |
+
msgid "Create a Beautiful Timeline In Minutes"
|
728 |
+
msgstr ""
|
729 |
+
|
730 |
+
#: pages/welcome.php:57
|
731 |
+
msgid ""
|
732 |
+
"Create a vertical and responsive, CSS3 animated timeline fast...without ever "
|
733 |
+
"writing a single line of code."
|
734 |
+
msgstr ""
|
735 |
+
|
736 |
+
#: pages/welcome.php:60
|
737 |
+
msgid "Font Awesome Included"
|
738 |
+
msgstr ""
|
739 |
+
|
740 |
+
#: pages/welcome.php:61
|
741 |
+
msgid ""
|
742 |
+
"Hundreds of icons to choose from to make your announcements really stand out!"
|
743 |
+
msgstr ""
|
744 |
+
|
745 |
+
#: pages/welcome.php:70
|
746 |
+
msgid "Intuitive Custom Post Creation Screen"
|
747 |
+
msgstr ""
|
748 |
+
|
749 |
+
#: pages/welcome.php:74
|
750 |
+
msgid "Manage Announcements Easily"
|
751 |
+
msgstr ""
|
752 |
+
|
753 |
+
#: pages/welcome.php:78
|
754 |
+
msgid "Style The Timeline"
|
755 |
+
msgstr ""
|
756 |
+
|
757 |
+
#: pages/welcome.php:86
|
758 |
+
msgid "Timeline Express // Sample Timeline"
|
759 |
+
msgstr ""
|
760 |
+
|
761 |
+
#: pages/welcome.php:98
|
762 |
+
msgid "this free plugin was made with"
|
763 |
+
msgstr ""
|
764 |
+
|
765 |
+
#: pages/welcome.php:98
|
766 |
+
msgid "Please consider making a"
|
767 |
+
msgstr ""
|
768 |
+
|
769 |
+
#: pages/welcome.php:98
|
770 |
+
msgid "donation"
|
771 |
+
msgstr ""
|
772 |
+
|
773 |
+
#: pages/welcome.php:98
|
774 |
+
msgid "if you need support in any way."
|
775 |
+
msgstr ""
|
776 |
+
|
777 |
+
#: pages/welcome.php:102
|
778 |
+
msgid "Keep Up With Me Elsewhere "
|
779 |
+
msgstr ""
|
780 |
+
|
781 |
+
#. #-#-#-#-# plugin.pot (Timeline Express 1.1.6.6) #-#-#-#-#
|
782 |
+
#. Plugin URI of the plugin/theme
|
783 |
+
#. #-#-#-#-# plugin.pot (Timeline Express 1.1.6.6) #-#-#-#-#
|
784 |
+
#. Author URI of the plugin/theme
|
785 |
+
msgid "http://www.evan-herman.com"
|
786 |
+
msgstr ""
|
787 |
+
|
788 |
+
#. Description of the plugin/theme
|
789 |
+
msgid ""
|
790 |
+
"Create a beautiful vertical, CSS3 animated and responsive timeline in "
|
791 |
+
"minutes flat without writing code."
|
792 |
+
msgstr ""
|
793 |
+
|
794 |
+
#. Author of the plugin/theme
|
795 |
+
msgid "Evan Herman"
|
796 |
+
msgstr ""
|
lib/about-metabox-template.php
CHANGED
@@ -41,10 +41,10 @@
|
|
41 |
<br />
|
42 |
<br />
|
43 |
<!-- social media buttons -->
|
44 |
-
<a href="https://profiles.wordpress.org/eherman24#content-plugins" title="WordPress" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL;
|
45 |
-
<a href="http://twitter.com/evanmherman" title="Twitter" target="_blank" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL;
|
46 |
-
<a href="https://www.linkedin.com/profile/view?id=46246110" title="Linkedin" target="_blank" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL;
|
47 |
-
<a href="http://www.evan-herman.com/feed/" title="RSS Feed" target="_blank" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL;
|
48 |
</section>
|
49 |
|
50 |
<em style="display:block;font-size:12px; text-align:center;margin:.5em 0;"><?php _e( 'this plugin was made with ' , 'timeline-express' ); ?><div class="dashicons dashicons-heart" style="line-height:1.2;"></div>, <?php _e( 'by' , 'timeline-express' ); ?> <a href="http://www.evan-herman.com" target="_blank">Evan Herman</a></em>
|
41 |
<br />
|
42 |
<br />
|
43 |
<!-- social media buttons -->
|
44 |
+
<a href="https://profiles.wordpress.org/eherman24#content-plugins" title="WordPress" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL; ?>images/wordpress-icon.png" style="border: 0px none;" alt="Evan Herman - WordPress Profile" height="24" width="24"></a>
|
45 |
+
<a href="http://twitter.com/evanmherman" title="Twitter" target="_blank" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL; ?>images/twitter.png" style="border: 0px none;" alt="Evan Herman - Twitter Profile" height="24" width="24"></a>
|
46 |
+
<a href="https://www.linkedin.com/profile/view?id=46246110" title="Linkedin" target="_blank" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL; ?>images/linkedin.png" alt="Evan Herman - LinkedIn Profile" border="0" height="24" width="24"></a>
|
47 |
+
<a href="http://www.evan-herman.com/feed/" title="RSS Feed" target="_blank" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL; ?>images/rss_icon.png" alt="Evan Herman - RSS Feed" border="0" height="24" width="24"></a>
|
48 |
</section>
|
49 |
|
50 |
<em style="display:block;font-size:12px; text-align:center;margin:.5em 0;"><?php _e( 'this plugin was made with ' , 'timeline-express' ); ?><div class="dashicons dashicons-heart" style="line-height:1.2;"></div>, <?php _e( 'by' , 'timeline-express' ); ?> <a href="http://www.evan-herman.com" target="_blank">Evan Herman</a></em>
|
lib/cmb_metaboxes/helpers/cmb_Meta_Box_Sanitize.php
CHANGED
@@ -1,346 +1,346 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* CMB field validation
|
5 |
-
* @since 0.0.4
|
6 |
-
*/
|
7 |
-
class cmb_Meta_Box_Sanitize {
|
8 |
-
|
9 |
-
/**
|
10 |
-
* A CMB field object
|
11 |
-
* @var cmb_Meta_Box_field object
|
12 |
-
*/
|
13 |
-
public $field;
|
14 |
-
|
15 |
-
/**
|
16 |
-
* Field's $_POST value
|
17 |
-
* @var mixed
|
18 |
-
*/
|
19 |
-
public $value;
|
20 |
-
|
21 |
-
/**
|
22 |
-
* Setup our class vars
|
23 |
-
* @since 1.1.0
|
24 |
-
* @param object $field A CMB field object
|
25 |
-
* @param mixed $value Field value
|
26 |
-
*/
|
27 |
-
public function __construct( $field, $value ) {
|
28 |
-
$this->field = $field;
|
29 |
-
$this->value = $value;
|
30 |
-
$this->object_id = cmb_Meta_Box::get_object_id();
|
31 |
-
$this->object_type = cmb_Meta_Box::get_object_type();
|
32 |
-
}
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Catchall method if field's 'sanitization_cb' is NOT defined, or field type does not have a corresponding validation method
|
36 |
-
* @since 1.0.0
|
37 |
-
* @param string $name Non-existent method name
|
38 |
-
* @param array $arguments All arguments passed to the method
|
39 |
-
*/
|
40 |
-
public function __call( $name, $arguments ) {
|
41 |
-
list( $value ) = $arguments;
|
42 |
-
return $this->default_sanitization( $value );
|
43 |
-
}
|
44 |
-
|
45 |
-
/**
|
46 |
-
* Default fallback sanitization method. Applies filters.
|
47 |
-
* @since 1.0.2
|
48 |
-
* @param mixed $value Meta value
|
49 |
-
*/
|
50 |
-
public function default_sanitization( $value ) {
|
51 |
-
|
52 |
-
// Allow field type validation via filter
|
53 |
-
$updated = apply_filters( 'cmb_validate_'. $this->field->type(), null, $value, $this->object_id, $this->field->args(), $this );
|
54 |
-
|
55 |
-
if ( null !== $updated )
|
56 |
-
return $updated;
|
57 |
-
|
58 |
-
switch ( $this->field->type() ) {
|
59 |
-
case 'wysiwyg':
|
60 |
-
// $value = wp_kses( $value );
|
61 |
-
// break;
|
62 |
-
case 'textarea_small':
|
63 |
-
return $this->textarea( $value );
|
64 |
-
case 'taxonomy_select':
|
65 |
-
case 'taxonomy_radio':
|
66 |
-
case 'taxonomy_multicheck':
|
67 |
-
if ( $this->field->args( 'taxonomy' ) ) {
|
68 |
-
return wp_set_object_terms( $this->object_id, $value, $this->field->args( 'taxonomy' ) );
|
69 |
-
}
|
70 |
-
case 'multicheck':
|
71 |
-
case 'file_list':
|
72 |
-
case 'oembed':
|
73 |
-
// no filtering
|
74 |
-
return $value;
|
75 |
-
default:
|
76 |
-
// Handle repeatable fields array
|
77 |
-
// We'll fallback to 'sanitize_text_field'
|
78 |
-
return is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : call_user_func( 'sanitize_text_field', $value );
|
79 |
-
}
|
80 |
-
}
|
81 |
-
|
82 |
-
/**
|
83 |
-
* Simple checkbox validation
|
84 |
-
* @since 1.0.1
|
85 |
-
* @param mixed $val 'on' or false
|
86 |
-
* @return mixed 'on' or false
|
87 |
-
*/
|
88 |
-
public function checkbox( $value ) {
|
89 |
-
return $value === 'on' ? 'on' : false;
|
90 |
-
}
|
91 |
-
|
92 |
-
/**
|
93 |
-
* Validate url in a meta value
|
94 |
-
* @since 1.0.1
|
95 |
-
* @param string $value Meta value
|
96 |
-
* @return string Empty string or escaped url
|
97 |
-
*/
|
98 |
-
public function text_url( $value ) {
|
99 |
-
$protocols = $this->field->args( 'protocols' );
|
100 |
-
// for repeatable
|
101 |
-
if ( is_array( $value ) ) {
|
102 |
-
foreach ( $value as $key => $val ) {
|
103 |
-
$value[ $key ] = $val ? esc_url_raw( $val, $protocols ) : $this->field->args( 'default' );
|
104 |
-
}
|
105 |
-
} else {
|
106 |
-
$value = $value ? esc_url_raw( $value, $protocols ) : $this->field->args( 'default' );
|
107 |
-
}
|
108 |
-
|
109 |
-
return $value;
|
110 |
-
}
|
111 |
-
|
112 |
-
public function colorpicker( $value ) {
|
113 |
-
// for repeatable
|
114 |
-
if ( is_array( $value ) ) {
|
115 |
-
$check = $value;
|
116 |
-
$value = array();
|
117 |
-
foreach ( $check as $key => $val ) {
|
118 |
-
if ( $val && '#' != $val ) {
|
119 |
-
$value[ $key ] = esc_attr( $val );
|
120 |
-
}
|
121 |
-
}
|
122 |
-
} else {
|
123 |
-
$value = ! $value || '#' == $value ? '' : esc_attr( $value );
|
124 |
-
}
|
125 |
-
return $value;
|
126 |
-
}
|
127 |
-
|
128 |
-
/**
|
129 |
-
* Validate email in a meta value
|
130 |
-
* @since 1.0.1
|
131 |
-
* @param string $value Meta value
|
132 |
-
* @return string Empty string or validated email
|
133 |
-
*/
|
134 |
-
public function text_email( $value ) {
|
135 |
-
// for repeatable
|
136 |
-
if ( is_array( $value ) ) {
|
137 |
-
foreach ( $value as $key => $val ) {
|
138 |
-
$val = trim( $val );
|
139 |
-
$value[ $key ] = is_email( $val ) ? $val : '';
|
140 |
-
}
|
141 |
-
} else {
|
142 |
-
$value = trim( $value );
|
143 |
-
$value = is_email( $value ) ? $value : '';
|
144 |
-
}
|
145 |
-
|
146 |
-
return $value;
|
147 |
-
}
|
148 |
-
|
149 |
-
/**
|
150 |
-
* Validate money in a meta value
|
151 |
-
* @since 1.0.1
|
152 |
-
* @param string $value Meta value
|
153 |
-
* @return string Empty string or validated money value
|
154 |
-
*/
|
155 |
-
public function text_money( $value ) {
|
156 |
-
|
157 |
-
global $wp_locale;
|
158 |
-
|
159 |
-
$search = array( $wp_locale->number_format['thousands_sep'], $wp_locale->number_format['decimal_point'] );
|
160 |
-
$replace = array( '', '.' );
|
161 |
-
|
162 |
-
// for repeatable
|
163 |
-
if ( is_array( $value ) ) {
|
164 |
-
foreach ( $value as $key => $val ) {
|
165 |
-
$value[ $key ] = number_format_i18n( (float) str_ireplace( $search, $replace, $val ), 2 );
|
166 |
-
}
|
167 |
-
} else {
|
168 |
-
$value = number_format_i18n( (float) str_ireplace( $search, $replace, $value ), 2 );
|
169 |
-
}
|
170 |
-
|
171 |
-
return $value;
|
172 |
-
}
|
173 |
-
|
174 |
-
/**
|
175 |
-
* Converts text date to timestamp
|
176 |
-
* @since 1.0.2
|
177 |
-
* @param string $value Meta value
|
178 |
-
* @return string Timestring
|
179 |
-
*/
|
180 |
-
public function text_date_timestamp( $value ) {
|
181 |
-
return is_array( $value ) ? array_map( 'strtotime', $value ) : strtotime( $value );
|
182 |
-
}
|
183 |
-
|
184 |
-
/**
|
185 |
-
* Datetime to timestamp
|
186 |
-
* @since 1.0.1
|
187 |
-
* @param string $value Meta value
|
188 |
-
* @return string Timestring
|
189 |
-
*/
|
190 |
-
public function text_datetime_timestamp( $value, $repeat = false ) {
|
191 |
-
|
192 |
-
$test = is_array( $value ) ? array_filter( $value ) : '';
|
193 |
-
if ( empty( $test ) )
|
194 |
-
return '';
|
195 |
-
|
196 |
-
if ( $repeat_value = $this->_check_repeat( $value, __FUNCTION__, $repeat ) )
|
197 |
-
return $repeat_value;
|
198 |
-
|
199 |
-
$value = strtotime( $value['date'] .' '. $value['time'] );
|
200 |
-
|
201 |
-
if ( $tz_offset = $this->field->field_timezone_offset() )
|
202 |
-
$value += $tz_offset;
|
203 |
-
|
204 |
-
return $value;
|
205 |
-
}
|
206 |
-
|
207 |
-
/**
|
208 |
-
* Datetime to imestamp with timezone
|
209 |
-
* @since 1.0.1
|
210 |
-
* @param string $value Meta value
|
211 |
-
* @return string Timestring
|
212 |
-
*/
|
213 |
-
public function text_datetime_timestamp_timezone( $value, $repeat = false ) {
|
214 |
-
|
215 |
-
$test = is_array( $value ) ? array_filter( $value ) : '';
|
216 |
-
if ( empty( $test ) )
|
217 |
-
return '';
|
218 |
-
|
219 |
-
if ( $repeat_value = $this->_check_repeat( $value, __FUNCTION__, $repeat ) )
|
220 |
-
return $repeat_value;
|
221 |
-
|
222 |
-
$tzstring = null;
|
223 |
-
|
224 |
-
if ( is_array( $value ) && array_key_exists( 'timezone', $value ) )
|
225 |
-
$tzstring = $value['timezone'];
|
226 |
-
|
227 |
-
if ( empty( $tzstring ) )
|
228 |
-
$tzstring = cmb_Meta_Box::timezone_string();
|
229 |
-
|
230 |
-
$offset = cmb_Meta_Box::timezone_offset( $tzstring, true );
|
231 |
-
|
232 |
-
if ( substr( $tzstring, 0, 3 ) === 'UTC' )
|
233 |
-
$tzstring = timezone_name_from_abbr( '', $offset, 0 );
|
234 |
-
|
235 |
-
$value = new DateTime( $value['date'] .' '. $value['time'], new DateTimeZone( $tzstring ) );
|
236 |
-
$value = serialize( $value );
|
237 |
-
|
238 |
-
return $value;
|
239 |
-
}
|
240 |
-
|
241 |
-
/**
|
242 |
-
* Sanitize textareas and wysiwyg fields
|
243 |
-
* @since 1.0.1
|
244 |
-
* @param string $value Meta value
|
245 |
-
* @return string Sanitized data
|
246 |
-
*/
|
247 |
-
public function textarea( $value ) {
|
248 |
-
return is_array( $value ) ? array_map( 'wp_kses_post', $value ) : wp_kses_post( $value );
|
249 |
-
}
|
250 |
-
|
251 |
-
/**
|
252 |
-
* Sanitize code textareas
|
253 |
-
* @since 1.0.2
|
254 |
-
* @param string $value Meta value
|
255 |
-
* @return string Sanitized data
|
256 |
-
*/
|
257 |
-
public function textarea_code( $value, $repeat = false ) {
|
258 |
-
if ( $repeat_value = $this->_check_repeat( $value, __FUNCTION__, $repeat ) )
|
259 |
-
return $repeat_value;
|
260 |
-
|
261 |
-
return htmlspecialchars_decode( stripslashes( $value ) );
|
262 |
-
}
|
263 |
-
|
264 |
-
/**
|
265 |
-
* Peforms saving of `file` attachement's ID
|
266 |
-
* @since 1.1.0
|
267 |
-
* @param string $value File url
|
268 |
-
*/
|
269 |
-
public function _save_file_id( $value ) {
|
270 |
-
$group = $this->field->group;
|
271 |
-
$args = $this->field->args();
|
272 |
-
$args['id'] = $args['_id'] . '_id';
|
273 |
-
|
274 |
-
unset( $args['_id'], $args['_name'] );
|
275 |
-
// And get new field object
|
276 |
-
$field = new cmb_Meta_Box_field( $args, $group );
|
277 |
-
$id_key = $field->_id();
|
278 |
-
$id_val_old = $field->escaped_value( 'absint' );
|
279 |
-
|
280 |
-
if ( $group ) {
|
281 |
-
// Check group $_POST data
|
282 |
-
$i = $group->index;
|
283 |
-
$base_id = $group->_id();
|
284 |
-
$id_val = isset( $_POST[ $base_id ][ $i ][ $id_key ] ) ? absint( $_POST[ $base_id ][ $i ][ $id_key ] ) : 0;
|
285 |
-
|
286 |
-
} else {
|
287 |
-
// Check standard $_POST data
|
288 |
-
$id_val = isset( $_POST[ $field->id() ] ) ? $_POST[ $field->id() ] : null;
|
289 |
-
|
290 |
-
}
|
291 |
-
|
292 |
-
// If there is no ID saved yet, try to get it from the url
|
293 |
-
if ( $value && ! $id_val ) {
|
294 |
-
$id_val = cmb_Meta_Box::image_id_from_url( $value );
|
295 |
-
}
|
296 |
-
|
297 |
-
if ( $group ) {
|
298 |
-
return array(
|
299 |
-
'attach_id' => $id_val,
|
300 |
-
'field_id' => $id_key
|
301 |
-
);
|
302 |
-
}
|
303 |
-
|
304 |
-
if ( $id_val && $id_val != $id_val_old ) {
|
305 |
-
return $field->update_data( $id_val );
|
306 |
-
} elseif ( empty( $id_val ) && $id_val_old ) {
|
307 |
-
return $field->remove_data( $old );
|
308 |
-
}
|
309 |
-
}
|
310 |
-
|
311 |
-
/**
|
312 |
-
* Handles saving of attachment post ID and sanitizing file url
|
313 |
-
* @since 1.1.0
|
314 |
-
* @param string $value File url
|
315 |
-
* @return string Sanitized url
|
316 |
-
*/
|
317 |
-
public function file( $value ) {
|
318 |
-
// If NOT specified to NOT save the file ID
|
319 |
-
if ( $this->field->args( 'save_id' ) ) {
|
320 |
-
$id_value = $this->_save_file_id( $value );
|
321 |
-
}
|
322 |
-
$clean = $this->text_url( $value );
|
323 |
-
|
324 |
-
// Return an array with url/id if saving a group field
|
325 |
-
return $this->field->group ? array_merge( array( 'url' => $clean), $id_value ) : $clean;
|
326 |
-
}
|
327 |
-
|
328 |
-
/**
|
329 |
-
* If repeating, loop through and re-apply sanitization method
|
330 |
-
* @since 1.1.0
|
331 |
-
* @param mixed $value Meta value
|
332 |
-
* @param string $method Class method
|
333 |
-
* @param bool $repeat Whether repeating or not
|
334 |
-
* @return mixed Sanitized value
|
335 |
-
*/
|
336 |
-
public function _check_repeat( $value, $method, $repeat ) {
|
337 |
-
if ( $repeat || ! $this->field->args( 'repeatable' ) )
|
338 |
-
return;
|
339 |
-
$new_value = array();
|
340 |
-
foreach ( $value as $iterator => $val ) {
|
341 |
-
$new_value[] = $this->$method( $val, true );
|
342 |
-
}
|
343 |
-
return $new_value;
|
344 |
-
}
|
345 |
-
|
346 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* CMB field validation
|
5 |
+
* @since 0.0.4
|
6 |
+
*/
|
7 |
+
class cmb_Meta_Box_Sanitize {
|
8 |
+
|
9 |
+
/**
|
10 |
+
* A CMB field object
|
11 |
+
* @var cmb_Meta_Box_field object
|
12 |
+
*/
|
13 |
+
public $field;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Field's $_POST value
|
17 |
+
* @var mixed
|
18 |
+
*/
|
19 |
+
public $value;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Setup our class vars
|
23 |
+
* @since 1.1.0
|
24 |
+
* @param object $field A CMB field object
|
25 |
+
* @param mixed $value Field value
|
26 |
+
*/
|
27 |
+
public function __construct( $field, $value ) {
|
28 |
+
$this->field = $field;
|
29 |
+
$this->value = $value;
|
30 |
+
$this->object_id = cmb_Meta_Box::get_object_id();
|
31 |
+
$this->object_type = cmb_Meta_Box::get_object_type();
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Catchall method if field's 'sanitization_cb' is NOT defined, or field type does not have a corresponding validation method
|
36 |
+
* @since 1.0.0
|
37 |
+
* @param string $name Non-existent method name
|
38 |
+
* @param array $arguments All arguments passed to the method
|
39 |
+
*/
|
40 |
+
public function __call( $name, $arguments ) {
|
41 |
+
list( $value ) = $arguments;
|
42 |
+
return $this->default_sanitization( $value );
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Default fallback sanitization method. Applies filters.
|
47 |
+
* @since 1.0.2
|
48 |
+
* @param mixed $value Meta value
|
49 |
+
*/
|
50 |
+
public function default_sanitization( $value ) {
|
51 |
+
|
52 |
+
// Allow field type validation via filter
|
53 |
+
$updated = apply_filters( 'cmb_validate_'. $this->field->type(), null, $value, $this->object_id, $this->field->args(), $this );
|
54 |
+
|
55 |
+
if ( null !== $updated )
|
56 |
+
return $updated;
|
57 |
+
|
58 |
+
switch ( $this->field->type() ) {
|
59 |
+
case 'wysiwyg':
|
60 |
+
// $value = wp_kses( $value );
|
61 |
+
// break;
|
62 |
+
case 'textarea_small':
|
63 |
+
return $this->textarea( $value );
|
64 |
+
case 'taxonomy_select':
|
65 |
+
case 'taxonomy_radio':
|
66 |
+
case 'taxonomy_multicheck':
|
67 |
+
if ( $this->field->args( 'taxonomy' ) ) {
|
68 |
+
return wp_set_object_terms( $this->object_id, $value, $this->field->args( 'taxonomy' ) );
|
69 |
+
}
|
70 |
+
case 'multicheck':
|
71 |
+
case 'file_list':
|
72 |
+
case 'oembed':
|
73 |
+
// no filtering
|
74 |
+
return $value;
|
75 |
+
default:
|
76 |
+
// Handle repeatable fields array
|
77 |
+
// We'll fallback to 'sanitize_text_field'
|
78 |
+
return is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : call_user_func( 'sanitize_text_field', $value );
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Simple checkbox validation
|
84 |
+
* @since 1.0.1
|
85 |
+
* @param mixed $val 'on' or false
|
86 |
+
* @return mixed 'on' or false
|
87 |
+
*/
|
88 |
+
public function checkbox( $value ) {
|
89 |
+
return $value === 'on' ? 'on' : false;
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Validate url in a meta value
|
94 |
+
* @since 1.0.1
|
95 |
+
* @param string $value Meta value
|
96 |
+
* @return string Empty string or escaped url
|
97 |
+
*/
|
98 |
+
public function text_url( $value ) {
|
99 |
+
$protocols = $this->field->args( 'protocols' );
|
100 |
+
// for repeatable
|
101 |
+
if ( is_array( $value ) ) {
|
102 |
+
foreach ( $value as $key => $val ) {
|
103 |
+
$value[ $key ] = $val ? esc_url_raw( $val, $protocols ) : $this->field->args( 'default' );
|
104 |
+
}
|
105 |
+
} else {
|
106 |
+
$value = $value ? esc_url_raw( $value, $protocols ) : $this->field->args( 'default' );
|
107 |
+
}
|
108 |
+
|
109 |
+
return $value;
|
110 |
+
}
|
111 |
+
|
112 |
+
public function colorpicker( $value ) {
|
113 |
+
// for repeatable
|
114 |
+
if ( is_array( $value ) ) {
|
115 |
+
$check = $value;
|
116 |
+
$value = array();
|
117 |
+
foreach ( $check as $key => $val ) {
|
118 |
+
if ( $val && '#' != $val ) {
|
119 |
+
$value[ $key ] = esc_attr( $val );
|
120 |
+
}
|
121 |
+
}
|
122 |
+
} else {
|
123 |
+
$value = ! $value || '#' == $value ? '' : esc_attr( $value );
|
124 |
+
}
|
125 |
+
return $value;
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Validate email in a meta value
|
130 |
+
* @since 1.0.1
|
131 |
+
* @param string $value Meta value
|
132 |
+
* @return string Empty string or validated email
|
133 |
+
*/
|
134 |
+
public function text_email( $value ) {
|
135 |
+
// for repeatable
|
136 |
+
if ( is_array( $value ) ) {
|
137 |
+
foreach ( $value as $key => $val ) {
|
138 |
+
$val = trim( $val );
|
139 |
+
$value[ $key ] = is_email( $val ) ? $val : '';
|
140 |
+
}
|
141 |
+
} else {
|
142 |
+
$value = trim( $value );
|
143 |
+
$value = is_email( $value ) ? $value : '';
|
144 |
+
}
|
145 |
+
|
146 |
+
return $value;
|
147 |
+
}
|
148 |
+
|
149 |
+
/**
|
150 |
+
* Validate money in a meta value
|
151 |
+
* @since 1.0.1
|
152 |
+
* @param string $value Meta value
|
153 |
+
* @return string Empty string or validated money value
|
154 |
+
*/
|
155 |
+
public function text_money( $value ) {
|
156 |
+
|
157 |
+
global $wp_locale;
|
158 |
+
|
159 |
+
$search = array( $wp_locale->number_format['thousands_sep'], $wp_locale->number_format['decimal_point'] );
|
160 |
+
$replace = array( '', '.' );
|
161 |
+
|
162 |
+
// for repeatable
|
163 |
+
if ( is_array( $value ) ) {
|
164 |
+
foreach ( $value as $key => $val ) {
|
165 |
+
$value[ $key ] = number_format_i18n( (float) str_ireplace( $search, $replace, $val ), 2 );
|
166 |
+
}
|
167 |
+
} else {
|
168 |
+
$value = number_format_i18n( (float) str_ireplace( $search, $replace, $value ), 2 );
|
169 |
+
}
|
170 |
+
|
171 |
+
return $value;
|
172 |
+
}
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Converts text date to timestamp
|
176 |
+
* @since 1.0.2
|
177 |
+
* @param string $value Meta value
|
178 |
+
* @return string Timestring
|
179 |
+
*/
|
180 |
+
public function text_date_timestamp( $value ) {
|
181 |
+
return is_array( $value ) ? array_map( 'strtotime', $value ) : strtotime( $value );
|
182 |
+
}
|
183 |
+
|
184 |
+
/**
|
185 |
+
* Datetime to timestamp
|
186 |
+
* @since 1.0.1
|
187 |
+
* @param string $value Meta value
|
188 |
+
* @return string Timestring
|
189 |
+
*/
|
190 |
+
public function text_datetime_timestamp( $value, $repeat = false ) {
|
191 |
+
|
192 |
+
$test = is_array( $value ) ? array_filter( $value ) : '';
|
193 |
+
if ( empty( $test ) )
|
194 |
+
return '';
|
195 |
+
|
196 |
+
if ( $repeat_value = $this->_check_repeat( $value, __FUNCTION__, $repeat ) )
|
197 |
+
return $repeat_value;
|
198 |
+
|
199 |
+
$value = strtotime( $value['date'] .' '. $value['time'] );
|
200 |
+
|
201 |
+
if ( $tz_offset = $this->field->field_timezone_offset() )
|
202 |
+
$value += $tz_offset;
|
203 |
+
|
204 |
+
return $value;
|
205 |
+
}
|
206 |
+
|
207 |
+
/**
|
208 |
+
* Datetime to imestamp with timezone
|
209 |
+
* @since 1.0.1
|
210 |
+
* @param string $value Meta value
|
211 |
+
* @return string Timestring
|
212 |
+
*/
|
213 |
+
public function text_datetime_timestamp_timezone( $value, $repeat = false ) {
|
214 |
+
|
215 |
+
$test = is_array( $value ) ? array_filter( $value ) : '';
|
216 |
+
if ( empty( $test ) )
|
217 |
+
return '';
|
218 |
+
|
219 |
+
if ( $repeat_value = $this->_check_repeat( $value, __FUNCTION__, $repeat ) )
|
220 |
+
return $repeat_value;
|
221 |
+
|
222 |
+
$tzstring = null;
|
223 |
+
|
224 |
+
if ( is_array( $value ) && array_key_exists( 'timezone', $value ) )
|
225 |
+
$tzstring = $value['timezone'];
|
226 |
+
|
227 |
+
if ( empty( $tzstring ) )
|
228 |
+
$tzstring = cmb_Meta_Box::timezone_string();
|
229 |
+
|
230 |
+
$offset = cmb_Meta_Box::timezone_offset( $tzstring, true );
|
231 |
+
|
232 |
+
if ( substr( $tzstring, 0, 3 ) === 'UTC' )
|
233 |
+
$tzstring = timezone_name_from_abbr( '', $offset, 0 );
|
234 |
+
|
235 |
+
$value = new DateTime( $value['date'] .' '. $value['time'], new DateTimeZone( $tzstring ) );
|
236 |
+
$value = serialize( $value );
|
237 |
+
|
238 |
+
return $value;
|
239 |
+
}
|
240 |
+
|
241 |
+
/**
|
242 |
+
* Sanitize textareas and wysiwyg fields
|
243 |
+
* @since 1.0.1
|
244 |
+
* @param string $value Meta value
|
245 |
+
* @return string Sanitized data
|
246 |
+
*/
|
247 |
+
public function textarea( $value ) {
|
248 |
+
return is_array( $value ) ? array_map( 'wp_kses_post', $value ) : wp_kses_post( $value );
|
249 |
+
}
|
250 |
+
|
251 |
+
/**
|
252 |
+
* Sanitize code textareas
|
253 |
+
* @since 1.0.2
|
254 |
+
* @param string $value Meta value
|
255 |
+
* @return string Sanitized data
|
256 |
+
*/
|
257 |
+
public function textarea_code( $value, $repeat = false ) {
|
258 |
+
if ( $repeat_value = $this->_check_repeat( $value, __FUNCTION__, $repeat ) )
|
259 |
+
return $repeat_value;
|
260 |
+
|
261 |
+
return htmlspecialchars_decode( stripslashes( $value ) );
|
262 |
+
}
|
263 |
+
|
264 |
+
/**
|
265 |
+
* Peforms saving of `file` attachement's ID
|
266 |
+
* @since 1.1.0
|
267 |
+
* @param string $value File url
|
268 |
+
*/
|
269 |
+
public function _save_file_id( $value ) {
|
270 |
+
$group = $this->field->group;
|
271 |
+
$args = $this->field->args();
|
272 |
+
$args['id'] = $args['_id'] . '_id';
|
273 |
+
|
274 |
+
unset( $args['_id'], $args['_name'] );
|
275 |
+
// And get new field object
|
276 |
+
$field = new cmb_Meta_Box_field( $args, $group );
|
277 |
+
$id_key = $field->_id();
|
278 |
+
$id_val_old = $field->escaped_value( 'absint' );
|
279 |
+
|
280 |
+
if ( $group ) {
|
281 |
+
// Check group $_POST data
|
282 |
+
$i = $group->index;
|
283 |
+
$base_id = $group->_id();
|
284 |
+
$id_val = isset( $_POST[ $base_id ][ $i ][ $id_key ] ) ? absint( $_POST[ $base_id ][ $i ][ $id_key ] ) : 0;
|
285 |
+
|
286 |
+
} else {
|
287 |
+
// Check standard $_POST data
|
288 |
+
$id_val = isset( $_POST[ $field->id() ] ) ? $_POST[ $field->id() ] : null;
|
289 |
+
|
290 |
+
}
|
291 |
+
|
292 |
+
// If there is no ID saved yet, try to get it from the url
|
293 |
+
if ( $value && ! $id_val ) {
|
294 |
+
$id_val = cmb_Meta_Box::image_id_from_url( $value );
|
295 |
+
}
|
296 |
+
|
297 |
+
if ( $group ) {
|
298 |
+
return array(
|
299 |
+
'attach_id' => $id_val,
|
300 |
+
'field_id' => $id_key
|
301 |
+
);
|
302 |
+
}
|
303 |
+
|
304 |
+
if ( $id_val && $id_val != $id_val_old ) {
|
305 |
+
return $field->update_data( $id_val );
|
306 |
+
} elseif ( empty( $id_val ) && $id_val_old ) {
|
307 |
+
return $field->remove_data( $old );
|
308 |
+
}
|
309 |
+
}
|
310 |
+
|
311 |
+
/**
|
312 |
+
* Handles saving of attachment post ID and sanitizing file url
|
313 |
+
* @since 1.1.0
|
314 |
+
* @param string $value File url
|
315 |
+
* @return string Sanitized url
|
316 |
+
*/
|
317 |
+
public function file( $value ) {
|
318 |
+
// If NOT specified to NOT save the file ID
|
319 |
+
if ( $this->field->args( 'save_id' ) ) {
|
320 |
+
$id_value = $this->_save_file_id( $value );
|
321 |
+
}
|
322 |
+
$clean = $this->text_url( $value );
|
323 |
+
|
324 |
+
// Return an array with url/id if saving a group field
|
325 |
+
return $this->field->group ? array_merge( array( 'url' => $clean), $id_value ) : $clean;
|
326 |
+
}
|
327 |
+
|
328 |
+
/**
|
329 |
+
* If repeating, loop through and re-apply sanitization method
|
330 |
+
* @since 1.1.0
|
331 |
+
* @param mixed $value Meta value
|
332 |
+
* @param string $method Class method
|
333 |
+
* @param bool $repeat Whether repeating or not
|
334 |
+
* @return mixed Sanitized value
|
335 |
+
*/
|
336 |
+
public function _check_repeat( $value, $method, $repeat ) {
|
337 |
+
if ( $repeat || ! $this->field->args( 'repeatable' ) )
|
338 |
+
return;
|
339 |
+
$new_value = array();
|
340 |
+
foreach ( $value as $iterator => $val ) {
|
341 |
+
$new_value[] = $this->$method( $val, true );
|
342 |
+
}
|
343 |
+
return $new_value;
|
344 |
+
}
|
345 |
+
|
346 |
+
}
|
lib/cmb_metaboxes/helpers/cmb_Meta_Box_Show_Filters.php
CHANGED
@@ -1,105 +1,105 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Show On Filters
|
5 |
-
* Use the 'cmb_show_on' filter to further refine the conditions under which a metabox is displayed.
|
6 |
-
* Below you can limit it by ID and page template
|
7 |
-
*
|
8 |
-
* All methods in this class are automatically filtered
|
9 |
-
*
|
10 |
-
* @since 1.0.0
|
11 |
-
*/
|
12 |
-
class cmb_Meta_Box_Show_Filters {
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Add metaboxes for an specific ID
|
16 |
-
* @since 1.0.0
|
17 |
-
* @param bool $display To display or not
|
18 |
-
* @param array $meta_box Metabox config array
|
19 |
-
* @return bool Whether to display this metabox on the current page.
|
20 |
-
*/
|
21 |
-
public static function check_id( $display, $meta_box ) {
|
22 |
-
|
23 |
-
if ( ! isset( $meta_box['show_on']['key'] ) || 'id' !== $meta_box['show_on']['key'] )
|
24 |
-
return $display;
|
25 |
-
|
26 |
-
$object_id = is_admin() ? cmb_Meta_Box::get_object_id() : @get_the_id();
|
27 |
-
|
28 |
-
if ( ! $object_id )
|
29 |
-
return false;
|
30 |
-
|
31 |
-
// If current page id is in the included array, display the metabox
|
32 |
-
return in_array( $object_id, (array) $meta_box['show_on']['value'] );
|
33 |
-
}
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Add metaboxes for an specific Page Template
|
37 |
-
* @since 1.0.0
|
38 |
-
* @param bool $display To display or not
|
39 |
-
* @param array $meta_box Metabox config array
|
40 |
-
* @return bool Whether to display this metabox on the current page.
|
41 |
-
*/
|
42 |
-
public static function check_page_template( $display, $meta_box ) {
|
43 |
-
|
44 |
-
if ( ! isset( $meta_box['show_on']['key'] ) || 'page-template' !== $meta_box['show_on']['key'] )
|
45 |
-
return $display;
|
46 |
-
|
47 |
-
$object_id = cmb_Meta_Box::get_object_id();
|
48 |
-
|
49 |
-
if ( ! $object_id || cmb_Meta_Box::get_object_type() !== 'post' )
|
50 |
-
return false;
|
51 |
-
|
52 |
-
// Get current template
|
53 |
-
$current_template = get_post_meta( $object_id, '_wp_page_template', true );
|
54 |
-
|
55 |
-
// See if there's a match
|
56 |
-
if ( $current_template && in_array( $current_template, (array) $meta_box['show_on']['value'] ) )
|
57 |
-
return true;
|
58 |
-
|
59 |
-
return false;
|
60 |
-
}
|
61 |
-
|
62 |
-
/**
|
63 |
-
* Only show options-page metaboxes on their options page (but only enforce on the admin side)
|
64 |
-
* @since 1.0.0
|
65 |
-
* @param bool $display To display or not
|
66 |
-
* @param array $meta_box Metabox config array
|
67 |
-
* @return bool Whether to display this metabox on the current page.
|
68 |
-
*/
|
69 |
-
public static function check_admin_page( $display, $meta_box ) {
|
70 |
-
|
71 |
-
// check if this is a 'options-page' metabox
|
72 |
-
if ( ! isset( $meta_box['show_on']['key'] ) || 'options-page' !== $meta_box['show_on']['key'] )
|
73 |
-
return $display;
|
74 |
-
|
75 |
-
// Enforce 'show_on' filter in the admin
|
76 |
-
if ( is_admin() ) {
|
77 |
-
|
78 |
-
// If there is no 'page' query var, our filter isn't applicable
|
79 |
-
if ( ! isset( $_GET['page'] ) )
|
80 |
-
return $display;
|
81 |
-
|
82 |
-
if ( ! isset( $meta_box['show_on']['value'] ) )
|
83 |
-
return false;
|
84 |
-
|
85 |
-
$pages = $meta_box['show_on']['value'];
|
86 |
-
|
87 |
-
if ( is_array( $pages ) ) {
|
88 |
-
foreach ( $pages as $page ) {
|
89 |
-
if ( $_GET['page'] == $page )
|
90 |
-
return true;
|
91 |
-
}
|
92 |
-
} else {
|
93 |
-
if ( $_GET['page'] == $pages )
|
94 |
-
return true;
|
95 |
-
}
|
96 |
-
|
97 |
-
return false;
|
98 |
-
|
99 |
-
}
|
100 |
-
|
101 |
-
// Allow options-page metaboxes to be displayed anywhere on the front-end
|
102 |
-
return true;
|
103 |
-
}
|
104 |
-
|
105 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Show On Filters
|
5 |
+
* Use the 'cmb_show_on' filter to further refine the conditions under which a metabox is displayed.
|
6 |
+
* Below you can limit it by ID and page template
|
7 |
+
*
|
8 |
+
* All methods in this class are automatically filtered
|
9 |
+
*
|
10 |
+
* @since 1.0.0
|
11 |
+
*/
|
12 |
+
class cmb_Meta_Box_Show_Filters {
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Add metaboxes for an specific ID
|
16 |
+
* @since 1.0.0
|
17 |
+
* @param bool $display To display or not
|
18 |
+
* @param array $meta_box Metabox config array
|
19 |
+
* @return bool Whether to display this metabox on the current page.
|
20 |
+
*/
|
21 |
+
public static function check_id( $display, $meta_box ) {
|
22 |
+
|
23 |
+
if ( ! isset( $meta_box['show_on']['key'] ) || 'id' !== $meta_box['show_on']['key'] )
|
24 |
+
return $display;
|
25 |
+
|
26 |
+
$object_id = is_admin() ? cmb_Meta_Box::get_object_id() : @get_the_id();
|
27 |
+
|
28 |
+
if ( ! $object_id )
|
29 |
+
return false;
|
30 |
+
|
31 |
+
// If current page id is in the included array, display the metabox
|
32 |
+
return in_array( $object_id, (array) $meta_box['show_on']['value'] );
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Add metaboxes for an specific Page Template
|
37 |
+
* @since 1.0.0
|
38 |
+
* @param bool $display To display or not
|
39 |
+
* @param array $meta_box Metabox config array
|
40 |
+
* @return bool Whether to display this metabox on the current page.
|
41 |
+
*/
|
42 |
+
public static function check_page_template( $display, $meta_box ) {
|
43 |
+
|
44 |
+
if ( ! isset( $meta_box['show_on']['key'] ) || 'page-template' !== $meta_box['show_on']['key'] )
|
45 |
+
return $display;
|
46 |
+
|
47 |
+
$object_id = cmb_Meta_Box::get_object_id();
|
48 |
+
|
49 |
+
if ( ! $object_id || cmb_Meta_Box::get_object_type() !== 'post' )
|
50 |
+
return false;
|
51 |
+
|
52 |
+
// Get current template
|
53 |
+
$current_template = get_post_meta( $object_id, '_wp_page_template', true );
|
54 |
+
|
55 |
+
// See if there's a match
|
56 |
+
if ( $current_template && in_array( $current_template, (array) $meta_box['show_on']['value'] ) )
|
57 |
+
return true;
|
58 |
+
|
59 |
+
return false;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Only show options-page metaboxes on their options page (but only enforce on the admin side)
|
64 |
+
* @since 1.0.0
|
65 |
+
* @param bool $display To display or not
|
66 |
+
* @param array $meta_box Metabox config array
|
67 |
+
* @return bool Whether to display this metabox on the current page.
|
68 |
+
*/
|
69 |
+
public static function check_admin_page( $display, $meta_box ) {
|
70 |
+
|
71 |
+
// check if this is a 'options-page' metabox
|
72 |
+
if ( ! isset( $meta_box['show_on']['key'] ) || 'options-page' !== $meta_box['show_on']['key'] )
|
73 |
+
return $display;
|
74 |
+
|
75 |
+
// Enforce 'show_on' filter in the admin
|
76 |
+
if ( is_admin() ) {
|
77 |
+
|
78 |
+
// If there is no 'page' query var, our filter isn't applicable
|
79 |
+
if ( ! isset( $_GET['page'] ) )
|
80 |
+
return $display;
|
81 |
+
|
82 |
+
if ( ! isset( $meta_box['show_on']['value'] ) )
|
83 |
+
return false;
|
84 |
+
|
85 |
+
$pages = $meta_box['show_on']['value'];
|
86 |
+
|
87 |
+
if ( is_array( $pages ) ) {
|
88 |
+
foreach ( $pages as $page ) {
|
89 |
+
if ( $_GET['page'] == $page )
|
90 |
+
return true;
|
91 |
+
}
|
92 |
+
} else {
|
93 |
+
if ( $_GET['page'] == $pages )
|
94 |
+
return true;
|
95 |
+
}
|
96 |
+
|
97 |
+
return false;
|
98 |
+
|
99 |
+
}
|
100 |
+
|
101 |
+
// Allow options-page metaboxes to be displayed anywhere on the front-end
|
102 |
+
return true;
|
103 |
+
}
|
104 |
+
|
105 |
+
}
|
lib/cmb_metaboxes/helpers/cmb_Meta_Box_ajax.php
CHANGED
@@ -1,203 +1,203 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* CMB ajax methods
|
5 |
-
* (i.e. a lot of work to get oEmbeds to work with non-post objects)
|
6 |
-
*
|
7 |
-
* @since 0.9.5
|
8 |
-
*/
|
9 |
-
class cmb_Meta_Box_ajax {
|
10 |
-
|
11 |
-
// A single instance of this class.
|
12 |
-
public static $instance = null;
|
13 |
-
// Whether to hijack the oembed cache system
|
14 |
-
public static $hijack = false;
|
15 |
-
public static $object_id = 0;
|
16 |
-
public static $embed_args = array();
|
17 |
-
public static $object_type = 'post';
|
18 |
-
|
19 |
-
/**
|
20 |
-
* Creates or returns an instance of this class.
|
21 |
-
* @since 0.1.0
|
22 |
-
* @return cmb_Meta_Box_ajax A single instance of this class.
|
23 |
-
*/
|
24 |
-
public static function get() {
|
25 |
-
if ( self::$instance === null )
|
26 |
-
self::$instance = new self();
|
27 |
-
|
28 |
-
return self::$instance;
|
29 |
-
}
|
30 |
-
|
31 |
-
/**
|
32 |
-
* Handles our oEmbed ajax request
|
33 |
-
* @since 0.9.5
|
34 |
-
* @return object oEmbed embed code | fallback | error message
|
35 |
-
*/
|
36 |
-
public function oembed_handler() {
|
37 |
-
|
38 |
-
// verify our nonce
|
39 |
-
if ( ! ( isset( $_REQUEST['cmb_ajax_nonce'], $_REQUEST['oembed_url'] ) && wp_verify_nonce( $_REQUEST['cmb_ajax_nonce'], 'ajax_nonce' ) ) )
|
40 |
-
die();
|
41 |
-
|
42 |
-
// sanitize our search string
|
43 |
-
$oembed_string = sanitize_text_field( $_REQUEST['oembed_url'] );
|
44 |
-
|
45 |
-
// send back error if empty
|
46 |
-
if ( empty( $oembed_string ) )
|
47 |
-
self::send_result( '<p class="ui-state-error-text">'. __( 'Please Try Again', 'cmb' ) .'</p>', false );
|
48 |
-
|
49 |
-
// Set width of embed
|
50 |
-
$embed_width = isset( $_REQUEST['oembed_width'] ) && intval( $_REQUEST['oembed_width'] ) < 640 ? intval( $_REQUEST['oembed_width'] ) : '640';
|
51 |
-
|
52 |
-
// set url
|
53 |
-
$oembed_url = esc_url( $oembed_string );
|
54 |
-
// set args
|
55 |
-
$embed_args = array( 'width' => $embed_width );
|
56 |
-
|
57 |
-
// Get embed code (or fallback link)
|
58 |
-
$html = self::get_oembed( $oembed_url, $_REQUEST['object_id'], array(
|
59 |
-
'object_type' => isset( $_REQUEST['object_type'] ) ? $_REQUEST['object_type'] : 'post',
|
60 |
-
'oembed_args' => $embed_args,
|
61 |
-
'field_id' => $_REQUEST['field_id'],
|
62 |
-
) );
|
63 |
-
|
64 |
-
self::send_result( $html );
|
65 |
-
|
66 |
-
}
|
67 |
-
|
68 |
-
/**
|
69 |
-
* Retrieves oEmbed from url/object ID
|
70 |
-
* @since 0.9.5
|
71 |
-
* @param string $url URL to retrieve oEmbed
|
72 |
-
* @param int $object_id Object ID
|
73 |
-
* @param array $args Arguments for method
|
74 |
-
* @return string html markup with embed or fallback
|
75 |
-
*/
|
76 |
-
public static function get_oembed( $url, $object_id, $args = array() ) {
|
77 |
-
global $wp_embed;
|
78 |
-
|
79 |
-
$oembed_url = esc_url( $url );
|
80 |
-
|
81 |
-
// Sanitize object_id
|
82 |
-
self::$object_id = is_numeric( $object_id ) ? absint( $object_id ) : sanitize_text_field( $object_id );
|
83 |
-
|
84 |
-
$args = wp_parse_args( $args, array(
|
85 |
-
'object_type' => 'post',
|
86 |
-
'oembed_args' => self::$embed_args,
|
87 |
-
'field_id' => false,
|
88 |
-
'cache_key' => false,
|
89 |
-
) );
|
90 |
-
|
91 |
-
self::$embed_args =& $args;
|
92 |
-
|
93 |
-
// set the post_ID so oEmbed won't fail
|
94 |
-
// wp-includes/class-wp-embed.php, WP_Embed::shortcode(), line 162
|
95 |
-
$wp_embed->post_ID = self::$object_id;
|
96 |
-
|
97 |
-
// Special scenario if NOT a post object
|
98 |
-
if ( isset( $args['object_type'] ) && $args['object_type'] != 'post' ) {
|
99 |
-
|
100 |
-
if ( 'options-page' == $args['object_type'] ) {
|
101 |
-
// bogus id to pass some numeric checks
|
102 |
-
// Issue with a VERY large WP install?
|
103 |
-
$wp_embed->post_ID = 1987645321;
|
104 |
-
// Use our own cache key to correspond to this field (vs one cache key per url)
|
105 |
-
$args['cache_key'] = $args['field_id'] .'_cache';
|
106 |
-
}
|
107 |
-
// Ok, we need to hijack the oembed cache system
|
108 |
-
self::$hijack = true;
|
109 |
-
self::$object_type = $args['object_type'];
|
110 |
-
|
111 |
-
// Gets ombed cache from our object's meta (vs postmeta)
|
112 |
-
add_filter( 'get_post_metadata', array( 'cmb_Meta_Box_ajax', 'hijack_oembed_cache_get' ), 10, 3 );
|
113 |
-
// Sets ombed cache in our object's meta (vs postmeta)
|
114 |
-
add_filter( 'update_post_metadata', array( 'cmb_Meta_Box_ajax', 'hijack_oembed_cache_set' ), 10, 4 );
|
115 |
-
|
116 |
-
}
|
117 |
-
|
118 |
-
$embed_args = '';
|
119 |
-
foreach ( $args['oembed_args'] as $key => $val ) {
|
120 |
-
$embed_args .= " $key=\"$val\"";
|
121 |
-
}
|
122 |
-
|
123 |
-
// ping WordPress for an embed
|
124 |
-
$check_embed = $wp_embed->run_shortcode( '[embed'. $embed_args .']'. $oembed_url .'[/embed]' );
|
125 |
-
|
126 |
-
// fallback that WordPress creates when no oEmbed was found
|
127 |
-
$fallback = $wp_embed->maybe_make_link( $oembed_url );
|
128 |
-
|
129 |
-
// Send back our embed
|
130 |
-
if ( $check_embed && $check_embed != $fallback )
|
131 |
-
return '<div class="embed_status">'. $check_embed .'<p class="cmb_remove_wrapper"><a href="#" class="cmb_remove_file_button" rel="'. $args['field_id'] .'">'. __( 'Remove Embed', 'cmb' ) .'</a></p></div>';
|
132 |
-
|
133 |
-
// Otherwise, send back error info that no oEmbeds were found
|
134 |
-
return '<p class="ui-state-error-text">'. sprintf( __( 'No oEmbed Results Found for %s. View more info at', 'cmb' ), $fallback ) .' <a href="http://codex.wordpress.org/Embeds" target="_blank">codex.wordpress.org/Embeds</a>.</p>';
|
135 |
-
|
136 |
-
}
|
137 |
-
|
138 |
-
/**
|
139 |
-
* Hijacks retrieving of cached oEmbed.
|
140 |
-
* Returns cached data from relevant object metadata (vs postmeta)
|
141 |
-
*
|
142 |
-
* @since 0.9.5
|
143 |
-
* @param boolean $check Whether to retrieve postmeta or override
|
144 |
-
* @param int $object_id Object ID
|
145 |
-
* @param string $meta_key Object metakey
|
146 |
-
* @return mixed Object's oEmbed cached data
|
147 |
-
*/
|
148 |
-
public static function hijack_oembed_cache_get( $check, $object_id, $meta_key ) {
|
149 |
-
|
150 |
-
if ( ! self::$hijack || ( self::$object_id != $object_id && 1987645321 !== $object_id ) )
|
151 |
-
return $check;
|
152 |
-
|
153 |
-
// get cached data
|
154 |
-
$data = 'options-page' === self::$object_type
|
155 |
-
? cmb_Meta_Box::get_option( self::$object_id, self::$embed_args['cache_key'] )
|
156 |
-
: get_metadata( self::$object_type, self::$object_id, $meta_key, true );
|
157 |
-
|
158 |
-
return $data;
|
159 |
-
}
|
160 |
-
|
161 |
-
/**
|
162 |
-
* Hijacks saving of cached oEmbed.
|
163 |
-
* Saves cached data to relevant object metadata (vs postmeta)
|
164 |
-
*
|
165 |
-
* @since 0.9.5
|
166 |
-
* @param boolean $check Whether to continue setting postmeta
|
167 |
-
* @param int $object_id Object ID to get postmeta from
|
168 |
-
* @param string $meta_key Postmeta's key
|
169 |
-
* @param mixed $meta_value Value of the postmeta to be saved
|
170 |
-
* @return boolean Whether to continue setting
|
171 |
-
*/
|
172 |
-
public static function hijack_oembed_cache_set( $check, $object_id, $meta_key, $meta_value ) {
|
173 |
-
if ( ! self::$hijack || ( self::$object_id != $object_id && 1987645321 !== $object_id ) )
|
174 |
-
return $check;
|
175 |
-
|
176 |
-
// Cache the result to our metadata
|
177 |
-
if ( 'options-page' === self::$object_type ) {
|
178 |
-
// Set the option
|
179 |
-
cmb_Meta_Box::update_option( self::$object_id, self::$embed_args['cache_key'], $meta_value, array( 'type' => 'oembed' ) );
|
180 |
-
// Save the option
|
181 |
-
cmb_Meta_Box::save_option( self::$object_id );
|
182 |
-
} else {
|
183 |
-
update_metadata( self::$object_type, self::$object_id, $meta_key, $meta_value );
|
184 |
-
}
|
185 |
-
|
186 |
-
// Anything other than `null` to cancel saving to postmeta
|
187 |
-
return true;
|
188 |
-
}
|
189 |
-
|
190 |
-
/**
|
191 |
-
* Helper to send json encoded response to ajax
|
192 |
-
* @since 0.9.5
|
193 |
-
* @param string $data Data to be shown via ajax
|
194 |
-
* @param boolean $success Success or fail
|
195 |
-
*/
|
196 |
-
public static function send_result( $data, $success = true ) {
|
197 |
-
$found = $success ? 'found' : 'not found';
|
198 |
-
// send back our encoded data
|
199 |
-
echo json_encode( array( 'result' => $data, 'id' => $found ) );
|
200 |
-
die();
|
201 |
-
}
|
202 |
-
|
203 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* CMB ajax methods
|
5 |
+
* (i.e. a lot of work to get oEmbeds to work with non-post objects)
|
6 |
+
*
|
7 |
+
* @since 0.9.5
|
8 |
+
*/
|
9 |
+
class cmb_Meta_Box_ajax {
|
10 |
+
|
11 |
+
// A single instance of this class.
|
12 |
+
public static $instance = null;
|
13 |
+
// Whether to hijack the oembed cache system
|
14 |
+
public static $hijack = false;
|
15 |
+
public static $object_id = 0;
|
16 |
+
public static $embed_args = array();
|
17 |
+
public static $object_type = 'post';
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Creates or returns an instance of this class.
|
21 |
+
* @since 0.1.0
|
22 |
+
* @return cmb_Meta_Box_ajax A single instance of this class.
|
23 |
+
*/
|
24 |
+
public static function get() {
|
25 |
+
if ( self::$instance === null )
|
26 |
+
self::$instance = new self();
|
27 |
+
|
28 |
+
return self::$instance;
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Handles our oEmbed ajax request
|
33 |
+
* @since 0.9.5
|
34 |
+
* @return object oEmbed embed code | fallback | error message
|
35 |
+
*/
|
36 |
+
public function oembed_handler() {
|
37 |
+
|
38 |
+
// verify our nonce
|
39 |
+
if ( ! ( isset( $_REQUEST['cmb_ajax_nonce'], $_REQUEST['oembed_url'] ) && wp_verify_nonce( $_REQUEST['cmb_ajax_nonce'], 'ajax_nonce' ) ) )
|
40 |
+
die();
|
41 |
+
|
42 |
+
// sanitize our search string
|
43 |
+
$oembed_string = sanitize_text_field( $_REQUEST['oembed_url'] );
|
44 |
+
|
45 |
+
// send back error if empty
|
46 |
+
if ( empty( $oembed_string ) )
|
47 |
+
self::send_result( '<p class="ui-state-error-text">'. __( 'Please Try Again', 'cmb' ) .'</p>', false );
|
48 |
+
|
49 |
+
// Set width of embed
|
50 |
+
$embed_width = isset( $_REQUEST['oembed_width'] ) && intval( $_REQUEST['oembed_width'] ) < 640 ? intval( $_REQUEST['oembed_width'] ) : '640';
|
51 |
+
|
52 |
+
// set url
|
53 |
+
$oembed_url = esc_url( $oembed_string );
|
54 |
+
// set args
|
55 |
+
$embed_args = array( 'width' => $embed_width );
|
56 |
+
|
57 |
+
// Get embed code (or fallback link)
|
58 |
+
$html = self::get_oembed( $oembed_url, $_REQUEST['object_id'], array(
|
59 |
+
'object_type' => isset( $_REQUEST['object_type'] ) ? $_REQUEST['object_type'] : 'post',
|
60 |
+
'oembed_args' => $embed_args,
|
61 |
+
'field_id' => $_REQUEST['field_id'],
|
62 |
+
) );
|
63 |
+
|
64 |
+
self::send_result( $html );
|
65 |
+
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Retrieves oEmbed from url/object ID
|
70 |
+
* @since 0.9.5
|
71 |
+
* @param string $url URL to retrieve oEmbed
|
72 |
+
* @param int $object_id Object ID
|
73 |
+
* @param array $args Arguments for method
|
74 |
+
* @return string html markup with embed or fallback
|
75 |
+
*/
|
76 |
+
public static function get_oembed( $url, $object_id, $args = array() ) {
|
77 |
+
global $wp_embed;
|
78 |
+
|
79 |
+
$oembed_url = esc_url( $url );
|
80 |
+
|
81 |
+
// Sanitize object_id
|
82 |
+
self::$object_id = is_numeric( $object_id ) ? absint( $object_id ) : sanitize_text_field( $object_id );
|
83 |
+
|
84 |
+
$args = wp_parse_args( $args, array(
|
85 |
+
'object_type' => 'post',
|
86 |
+
'oembed_args' => self::$embed_args,
|
87 |
+
'field_id' => false,
|
88 |
+
'cache_key' => false,
|
89 |
+
) );
|
90 |
+
|
91 |
+
self::$embed_args =& $args;
|
92 |
+
|
93 |
+
// set the post_ID so oEmbed won't fail
|
94 |
+
// wp-includes/class-wp-embed.php, WP_Embed::shortcode(), line 162
|
95 |
+
$wp_embed->post_ID = self::$object_id;
|
96 |
+
|
97 |
+
// Special scenario if NOT a post object
|
98 |
+
if ( isset( $args['object_type'] ) && $args['object_type'] != 'post' ) {
|
99 |
+
|
100 |
+
if ( 'options-page' == $args['object_type'] ) {
|
101 |
+
// bogus id to pass some numeric checks
|
102 |
+
// Issue with a VERY large WP install?
|
103 |
+
$wp_embed->post_ID = 1987645321;
|
104 |
+
// Use our own cache key to correspond to this field (vs one cache key per url)
|
105 |
+
$args['cache_key'] = $args['field_id'] .'_cache';
|
106 |
+
}
|
107 |
+
// Ok, we need to hijack the oembed cache system
|
108 |
+
self::$hijack = true;
|
109 |
+
self::$object_type = $args['object_type'];
|
110 |
+
|
111 |
+
// Gets ombed cache from our object's meta (vs postmeta)
|
112 |
+
add_filter( 'get_post_metadata', array( 'cmb_Meta_Box_ajax', 'hijack_oembed_cache_get' ), 10, 3 );
|
113 |
+
// Sets ombed cache in our object's meta (vs postmeta)
|
114 |
+
add_filter( 'update_post_metadata', array( 'cmb_Meta_Box_ajax', 'hijack_oembed_cache_set' ), 10, 4 );
|
115 |
+
|
116 |
+
}
|
117 |
+
|
118 |
+
$embed_args = '';
|
119 |
+
foreach ( $args['oembed_args'] as $key => $val ) {
|
120 |
+
$embed_args .= " $key=\"$val\"";
|
121 |
+
}
|
122 |
+
|
123 |
+
// ping WordPress for an embed
|
124 |
+
$check_embed = $wp_embed->run_shortcode( '[embed'. $embed_args .']'. $oembed_url .'[/embed]' );
|
125 |
+
|
126 |
+
// fallback that WordPress creates when no oEmbed was found
|
127 |
+
$fallback = $wp_embed->maybe_make_link( $oembed_url );
|
128 |
+
|
129 |
+
// Send back our embed
|
130 |
+
if ( $check_embed && $check_embed != $fallback )
|
131 |
+
return '<div class="embed_status">'. $check_embed .'<p class="cmb_remove_wrapper"><a href="#" class="cmb_remove_file_button" rel="'. $args['field_id'] .'">'. __( 'Remove Embed', 'cmb' ) .'</a></p></div>';
|
132 |
+
|
133 |
+
// Otherwise, send back error info that no oEmbeds were found
|
134 |
+
return '<p class="ui-state-error-text">'. sprintf( __( 'No oEmbed Results Found for %s. View more info at', 'cmb' ), $fallback ) .' <a href="http://codex.wordpress.org/Embeds" target="_blank">codex.wordpress.org/Embeds</a>.</p>';
|
135 |
+
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* Hijacks retrieving of cached oEmbed.
|
140 |
+
* Returns cached data from relevant object metadata (vs postmeta)
|
141 |
+
*
|
142 |
+
* @since 0.9.5
|
143 |
+
* @param boolean $check Whether to retrieve postmeta or override
|
144 |
+
* @param int $object_id Object ID
|
145 |
+
* @param string $meta_key Object metakey
|
146 |
+
* @return mixed Object's oEmbed cached data
|
147 |
+
*/
|
148 |
+
public static function hijack_oembed_cache_get( $check, $object_id, $meta_key ) {
|
149 |
+
|
150 |
+
if ( ! self::$hijack || ( self::$object_id != $object_id && 1987645321 !== $object_id ) )
|
151 |
+
return $check;
|
152 |
+
|
153 |
+
// get cached data
|
154 |
+
$data = 'options-page' === self::$object_type
|
155 |
+
? cmb_Meta_Box::get_option( self::$object_id, self::$embed_args['cache_key'] )
|
156 |
+
: get_metadata( self::$object_type, self::$object_id, $meta_key, true );
|
157 |
+
|
158 |
+
return $data;
|
159 |
+
}
|
160 |
+
|
161 |
+
/**
|
162 |
+
* Hijacks saving of cached oEmbed.
|
163 |
+
* Saves cached data to relevant object metadata (vs postmeta)
|
164 |
+
*
|
165 |
+
* @since 0.9.5
|
166 |
+
* @param boolean $check Whether to continue setting postmeta
|
167 |
+
* @param int $object_id Object ID to get postmeta from
|
168 |
+
* @param string $meta_key Postmeta's key
|
169 |
+
* @param mixed $meta_value Value of the postmeta to be saved
|
170 |
+
* @return boolean Whether to continue setting
|
171 |
+
*/
|
172 |
+
public static function hijack_oembed_cache_set( $check, $object_id, $meta_key, $meta_value ) {
|
173 |
+
if ( ! self::$hijack || ( self::$object_id != $object_id && 1987645321 !== $object_id ) )
|
174 |
+
return $check;
|
175 |
+
|
176 |
+
// Cache the result to our metadata
|
177 |
+
if ( 'options-page' === self::$object_type ) {
|
178 |
+
// Set the option
|
179 |
+
cmb_Meta_Box::update_option( self::$object_id, self::$embed_args['cache_key'], $meta_value, array( 'type' => 'oembed' ) );
|
180 |
+
// Save the option
|
181 |
+
cmb_Meta_Box::save_option( self::$object_id );
|
182 |
+
} else {
|
183 |
+
update_metadata( self::$object_type, self::$object_id, $meta_key, $meta_value );
|
184 |
+
}
|
185 |
+
|
186 |
+
// Anything other than `null` to cancel saving to postmeta
|
187 |
+
return true;
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Helper to send json encoded response to ajax
|
192 |
+
* @since 0.9.5
|
193 |
+
* @param string $data Data to be shown via ajax
|
194 |
+
* @param boolean $success Success or fail
|
195 |
+
*/
|
196 |
+
public static function send_result( $data, $success = true ) {
|
197 |
+
$found = $success ? 'found' : 'not found';
|
198 |
+
// send back our encoded data
|
199 |
+
echo json_encode( array( 'result' => $data, 'id' => $found ) );
|
200 |
+
die();
|
201 |
+
}
|
202 |
+
|
203 |
+
}
|
lib/cmb_metaboxes/helpers/cmb_Meta_Box_field.php
CHANGED
@@ -1,497 +1,497 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* CMB field class
|
5 |
-
* @since 1.1.0
|
6 |
-
*/
|
7 |
-
class cmb_Meta_Box_field {
|
8 |
-
|
9 |
-
/**
|
10 |
-
* Metabox object id
|
11 |
-
* @var mixed
|
12 |
-
* @since 1.1.0
|
13 |
-
*/
|
14 |
-
public $object_id;
|
15 |
-
|
16 |
-
/**
|
17 |
-
* Metabox object type
|
18 |
-
* @var mixed
|
19 |
-
* @since 1.1.0
|
20 |
-
*/
|
21 |
-
public $object_type;
|
22 |
-
|
23 |
-
/**
|
24 |
-
* Field arguments
|
25 |
-
* @var mixed
|
26 |
-
* @since 1.1.0
|
27 |
-
*/
|
28 |
-
public $args;
|
29 |
-
|
30 |
-
/**
|
31 |
-
* Field group object
|
32 |
-
* @var mixed
|
33 |
-
* @since 1.1.0
|
34 |
-
*/
|
35 |
-
public $group;
|
36 |
-
|
37 |
-
/**
|
38 |
-
* Field meta value
|
39 |
-
* @var mixed
|
40 |
-
* @since 1.1.0
|
41 |
-
*/
|
42 |
-
public $value;
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Constructs our field object
|
46 |
-
* @since 1.1.0
|
47 |
-
* @param array $field_args Field arguments
|
48 |
-
* @param array $group_field (optional) Group field object
|
49 |
-
*/
|
50 |
-
public function __construct( $field_args, $group_field = null ) {
|
51 |
-
$this->object_id = cmb_Meta_Box::get_object_id();
|
52 |
-
$this->object_type = cmb_Meta_Box::get_object_type();
|
53 |
-
$this->group = ! empty( $group_field ) ? $group_field : false;
|
54 |
-
$this->args = $this->_set_field_defaults( $field_args );
|
55 |
-
|
56 |
-
// Allow an override for the field's value
|
57 |
-
// (assuming no one would want to save 'cmb_no_override_val' as a value)
|
58 |
-
$this->value = apply_filters( 'cmb_override_meta_value', 'cmb_no_override_val', $this->object_id, $this->args(), $this->object_type, $this );
|
59 |
-
|
60 |
-
// If no override, get our meta
|
61 |
-
$this->value = 'cmb_no_override_val' === $this->value
|
62 |
-
? $this->get_data()
|
63 |
-
: $this->value;
|
64 |
-
}
|
65 |
-
|
66 |
-
/**
|
67 |
-
* Non-existent methods fallback to checking for field arguments of the same name
|
68 |
-
* @since 1.1.0
|
69 |
-
* @param string $name Method name
|
70 |
-
* @param array $arguments Array of passed-in arguments
|
71 |
-
* @return mixed Value of field argument
|
72 |
-
*/
|
73 |
-
public function __call( $name, $arguments ) {
|
74 |
-
$key = isset( $arguments[0] ) ? $arguments[0] : false;
|
75 |
-
return $this->args( $name, $key );
|
76 |
-
}
|
77 |
-
|
78 |
-
/**
|
79 |
-
* Retrieves the field id
|
80 |
-
* @since 1.1.0
|
81 |
-
* @param boolean $raw Whether to retrieve pre-modidifed id
|
82 |
-
* @return string Field id
|
83 |
-
*/
|
84 |
-
public function id( $raw = false ) {
|
85 |
-
$id = $raw ? '_id' : 'id';
|
86 |
-
return $this->args( $id );
|
87 |
-
}
|
88 |
-
|
89 |
-
/**
|
90 |
-
* Get a field argument
|
91 |
-
* @since 1.1.0
|
92 |
-
* @param string $key Argument to check
|
93 |
-
* @param string $key Sub argument to check
|
94 |
-
* @return mixed Argument value or false if non-existent
|
95 |
-
*/
|
96 |
-
public function args( $key = '', $_key = '' ) {
|
97 |
-
$vars = $this->_data( 'args', $key );
|
98 |
-
if ( $_key ) {
|
99 |
-
return isset( $vars[ $_key ] ) ? $vars[ $_key ] : false;
|
100 |
-
}
|
101 |
-
return $vars;
|
102 |
-
}
|
103 |
-
|
104 |
-
/**
|
105 |
-
* Get Field's value
|
106 |
-
* @since 1.1.0
|
107 |
-
* @param string $key If value is an array, is used to get array key->value
|
108 |
-
* @return mixed Field value or false if non-existent
|
109 |
-
*/
|
110 |
-
public function value( $key = '' ) {
|
111 |
-
return $this->_data( 'value', $key );
|
112 |
-
}
|
113 |
-
|
114 |
-
/**
|
115 |
-
* Retrieve a portion of a field property
|
116 |
-
* @since 1.1.0
|
117 |
-
* @param string $var Field property to check
|
118 |
-
* @param string $key Field property array key to check
|
119 |
-
* @return mixed Queried property value or false
|
120 |
-
*/
|
121 |
-
public function _data( $var, $key = '' ) {
|
122 |
-
$vars = $this->$var;
|
123 |
-
if ( $key ) {
|
124 |
-
return isset( $vars[ $key ] ) ? $vars[ $key ] : false;
|
125 |
-
}
|
126 |
-
return $vars;
|
127 |
-
}
|
128 |
-
|
129 |
-
/**
|
130 |
-
* Retrieves metadata/option data
|
131 |
-
* @since 1.0.1
|
132 |
-
* @param string $field_id Meta key/Option array key
|
133 |
-
* @return mixed Meta/Option value
|
134 |
-
*/
|
135 |
-
public function get_data( $field_id = '', $args = array() ) {
|
136 |
-
if ( $field_id ) {
|
137 |
-
$args['field_id'] = $field_id;
|
138 |
-
} else if ( $this->group ) {
|
139 |
-
$args['field_id'] = $this->group->id();
|
140 |
-
}
|
141 |
-
extract( $this->data_args( $args ) );
|
142 |
-
|
143 |
-
$data = 'options-page' === $type
|
144 |
-
? cmb_Meta_Box::get_option( $id, $field_id )
|
145 |
-
: get_metadata( $type, $id, $field_id, ( $single || $repeat ) /* If multicheck this can be multiple values */ );
|
146 |
-
|
147 |
-
if ( $this->group && $data ) {
|
148 |
-
$data = isset( $data[ $this->group->args( 'count' ) ][ $this->args( '_id' ) ] )
|
149 |
-
? $data[ $this->group->args( 'count' ) ][ $this->args( '_id' ) ]
|
150 |
-
: false;
|
151 |
-
}
|
152 |
-
return $data;
|
153 |
-
}
|
154 |
-
|
155 |
-
/**
|
156 |
-
* Updates metadata/option data
|
157 |
-
* @since 1.0.1
|
158 |
-
* @param mixed $value Value to update data with
|
159 |
-
* @param bool $single Whether data is an array (add_metadata)
|
160 |
-
*/
|
161 |
-
public function update_data( $new_value, $single = true ) {
|
162 |
-
extract( $this->data_args( array( 'new_value' => $new_value, 'single' => $single ) ) );
|
163 |
-
|
164 |
-
$new_value = $repeat ? array_values( $new_value ) : $new_value;
|
165 |
-
|
166 |
-
if ( 'options-page' === $type )
|
167 |
-
return cmb_Meta_Box::update_option( $id, $field_id, $new_value, $single );
|
168 |
-
|
169 |
-
if ( ! $single )
|
170 |
-
return add_metadata( $type, $id, $field_id, $new_value, false );
|
171 |
-
|
172 |
-
return update_metadata( $type, $id, $field_id, $new_value );
|
173 |
-
}
|
174 |
-
|
175 |
-
/**
|
176 |
-
* Removes/updates metadata/option data
|
177 |
-
* @since 1.0.1
|
178 |
-
* @param string $old Old value
|
179 |
-
*/
|
180 |
-
public function remove_data( $old = '' ) {
|
181 |
-
extract( $this->data_args() );
|
182 |
-
|
183 |
-
return 'options-page' === $type
|
184 |
-
? cmb_Meta_Box::remove_option( $id, $field_id )
|
185 |
-
: delete_metadata( $type, $id, $field_id, $old );
|
186 |
-
}
|
187 |
-
|
188 |
-
/**
|
189 |
-
* data variables for get/set data methods
|
190 |
-
* @since 1.1.0
|
191 |
-
* @param array $args Override arguments
|
192 |
-
* @return array Updated arguments
|
193 |
-
*/
|
194 |
-
public function data_args( $args = array() ) {
|
195 |
-
$args = wp_parse_args( $args, array(
|
196 |
-
'type' => $this->object_type,
|
197 |
-
'id' => $this->object_id,
|
198 |
-
'field_id' => $this->id( true ),
|
199 |
-
'repeat' => $this->args( 'repeatable' ),
|
200 |
-
'single' => ! $this->args( 'multiple' ),
|
201 |
-
) );
|
202 |
-
return $args;
|
203 |
-
}
|
204 |
-
|
205 |
-
/**
|
206 |
-
* Checks if field has a registered validation callback
|
207 |
-
* @since 1.0.1
|
208 |
-
* @param mixed $meta_value Meta value
|
209 |
-
* @return mixed Possibly validated meta value
|
210 |
-
*/
|
211 |
-
public function sanitization_cb( $meta_value ) {
|
212 |
-
if ( empty( $meta_value ) )
|
213 |
-
return $meta_value;
|
214 |
-
|
215 |
-
// Check if the field has a registered validation callback
|
216 |
-
$cb = $this->maybe_callback( 'sanitization_cb' );
|
217 |
-
if ( false === $cb ) {
|
218 |
-
// If requestion NO validation, return meta value
|
219 |
-
return $meta_value;
|
220 |
-
} elseif ( $cb ) {
|
221 |
-
// Ok, callback is good, let's run it.
|
222 |
-
return call_user_func( $cb, $meta_value, $this->args(), $this );
|
223 |
-
}
|
224 |
-
|
225 |
-
$clean = new cmb_Meta_Box_Sanitize( $this, $meta_value );
|
226 |
-
// Validation via 'cmb_Meta_Box_Sanitize' (with fallback filter)
|
227 |
-
return $clean->{$this->type()}( $meta_value );
|
228 |
-
}
|
229 |
-
|
230 |
-
/**
|
231 |
-
* Checks if field has a callback value
|
232 |
-
* @since 1.0.1
|
233 |
-
* @param string $cb Callback string
|
234 |
-
* @return mixed NULL, false for NO validation, or $cb string if it exists.
|
235 |
-
*/
|
236 |
-
public function maybe_callback( $cb ) {
|
237 |
-
$field_args = $this->args();
|
238 |
-
if ( ! isset( $field_args[ $cb ] ) )
|
239 |
-
return;
|
240 |
-
|
241 |
-
// Check if metabox is requesting NO validation
|
242 |
-
$cb = false !== $field_args[ $cb ] && 'false' !== $field_args[ $cb ] ? $field_args[ $cb ] : false;
|
243 |
-
|
244 |
-
// If requestion NO validation, return false
|
245 |
-
if ( ! $cb )
|
246 |
-
return false;
|
247 |
-
|
248 |
-
if ( is_callable( $cb ) )
|
249 |
-
return $cb;
|
250 |
-
}
|
251 |
-
|
252 |
-
/**
|
253 |
-
* Determine if current type is excempt from escaping
|
254 |
-
* @since 1.1.0
|
255 |
-
* @return bool True if exempt
|
256 |
-
*/
|
257 |
-
public function escaping_exception() {
|
258 |
-
// These types cannot be escaped
|
259 |
-
return in_array( $this->type(), array(
|
260 |
-
'file_list',
|
261 |
-
'multicheck',
|
262 |
-
'text_datetime_timestamp_timezone',
|
263 |
-
) );
|
264 |
-
}
|
265 |
-
|
266 |
-
/**
|
267 |
-
* Determine if current type cannot be repeatable
|
268 |
-
* @since 1.1.0
|
269 |
-
* @param string $type Field type to check
|
270 |
-
* @return bool True if type cannot be repeatable
|
271 |
-
*/
|
272 |
-
public function repeatable_exception( $type ) {
|
273 |
-
// These types cannot be escaped
|
274 |
-
return in_array( $type, array(
|
275 |
-
'file', // Use file_list
|
276 |
-
'radio',
|
277 |
-
'title',
|
278 |
-
'group',
|
279 |
-
// @todo Ajax load wp_editor: http://wordpress.stackexchange.com/questions/51776/how-to-load-wp-editor-through-ajax-jquery
|
280 |
-
'wysiwyg',
|
281 |
-
'checkbox',
|
282 |
-
'radio_inline',
|
283 |
-
'taxonomy_radio',
|
284 |
-
'taxonomy_select',
|
285 |
-
'taxonomy_multicheck',
|
286 |
-
) );
|
287 |
-
}
|
288 |
-
|
289 |
-
/**
|
290 |
-
* Escape the value before output. Defaults to 'esc_attr()'
|
291 |
-
* @since 1.0.1
|
292 |
-
* @param mixed $meta_value Meta value
|
293 |
-
* @param mixed $func Escaping function (if not esc_attr())
|
294 |
-
* @return mixed Final value
|
295 |
-
*/
|
296 |
-
public function escaped_value( $func = 'esc_attr', $meta_value = '' ) {
|
297 |
-
|
298 |
-
if ( isset( $this->escaped_value ) )
|
299 |
-
return $this->escaped_value;
|
300 |
-
|
301 |
-
$meta_value = $meta_value ? $meta_value : $this->value();
|
302 |
-
// Check if the field has a registered escaping callback
|
303 |
-
$cb = $this->maybe_callback( 'escape_cb' );
|
304 |
-
if ( false === $cb || $this->escaping_exception() ) {
|
305 |
-
// If requesting NO escaping, return meta value
|
306 |
-
return ! empty( $meta_value ) ? $meta_value : $this->args( 'default' );
|
307 |
-
} elseif ( $cb ) {
|
308 |
-
// Ok, callback is good, let's run it.
|
309 |
-
return call_user_func( $cb, $meta_value, $this->args(), $this );
|
310 |
-
}
|
311 |
-
|
312 |
-
// Or custom escaping filter can be used
|
313 |
-
$esc = apply_filters( 'cmb_types_esc_'. $this->type(), null, $meta_value, $this->args(), $this );
|
314 |
-
if ( null !== $esc ) {
|
315 |
-
return $esc;
|
316 |
-
}
|
317 |
-
|
318 |
-
// escaping function passed in?
|
319 |
-
$func = $func ? $func : 'esc_attr';
|
320 |
-
$meta_value = ! empty( $meta_value ) ? $meta_value : $this->args( 'default' );
|
321 |
-
|
322 |
-
if ( is_array( $meta_value ) ) {
|
323 |
-
foreach ( $meta_value as $key => $value ) {
|
324 |
-
$meta_value[ $key ] = call_user_func( $func, $value );
|
325 |
-
}
|
326 |
-
} else {
|
327 |
-
$meta_value = call_user_func( $func, $meta_value );
|
328 |
-
}
|
329 |
-
|
330 |
-
$this->escaped_value = $meta_value;
|
331 |
-
return $this->escaped_value;
|
332 |
-
}
|
333 |
-
|
334 |
-
/**
|
335 |
-
* Offset a time value based on timezone
|
336 |
-
* @since 1.0.0
|
337 |
-
* @return string Offset time string
|
338 |
-
*/
|
339 |
-
public function field_timezone_offset() {
|
340 |
-
return cmb_Meta_Box::timezone_offset( $this->field_timezone() );
|
341 |
-
}
|
342 |
-
|
343 |
-
/**
|
344 |
-
* Return timezone string
|
345 |
-
* @since 1.0.0
|
346 |
-
* @return string Timezone string
|
347 |
-
*/
|
348 |
-
public function field_timezone() {
|
349 |
-
|
350 |
-
// Is timezone arg set?
|
351 |
-
if ( $this->args( 'timezone' ) ) {
|
352 |
-
return $this->args( 'timezone' ) ;
|
353 |
-
}
|
354 |
-
// Is there another meta key with a timezone stored as its value we should use?
|
355 |
-
else if ( $this->args( 'timezone_meta_key' ) ) {
|
356 |
-
return $this->get_data( $this->args( 'timezone_meta_key' ) );
|
357 |
-
}
|
358 |
-
|
359 |
-
return false;
|
360 |
-
}
|
361 |
-
|
362 |
-
/**
|
363 |
-
* Render a field row
|
364 |
-
* @since 1.0.0
|
365 |
-
*/
|
366 |
-
public function render_field() {
|
367 |
-
|
368 |
-
// If field is requesting to not be shown on the front-end
|
369 |
-
if ( ! is_admin() && ! $this->args( 'on_front' ) )
|
370 |
-
return;
|
371 |
-
|
372 |
-
// If field is requesting to be conditionally shown
|
373 |
-
if ( is_callable( $this->args( 'show_on_cb' ) ) && ! call_user_func( $this->args( 'show_on_cb' ), $this ) )
|
374 |
-
return;
|
375 |
-
|
376 |
-
$classes = 'cmb-type-'. sanitize_html_class( $this->type() );
|
377 |
-
$classes .= ' cmb_id_'. sanitize_html_class( $this->id() );
|
378 |
-
$classes .= $this->args( 'repeatable' ) ? ' cmb-repeat' : '';
|
379 |
-
// 'inline' flag, or _inline in the field type, set to true
|
380 |
-
$classes .= $this->args( 'inline' ) ? ' cmb-inline' : '';
|
381 |
-
$is_side = 'side' === $this->args( 'context' );
|
382 |
-
|
383 |
-
printf( "<tr class=\"%s\">\n", $classes );
|
384 |
-
|
385 |
-
if ( 'title' == $this->type() || ! $this->args( 'show_names' ) || $is_side ) {
|
386 |
-
echo "\t<td colspan=\"2\">\n";
|
387 |
-
|
388 |
-
if ( ! $this->args( 'show_names' ) || $is_side ) {
|
389 |
-
$style = ! $is_side || 'title' == $this->type() ? ' style="display:none;"' : '';
|
390 |
-
printf( "\n<label%s for=\"%s\">%s</label>\n", $style, $this->id(), $this->args( 'name' ) );
|
391 |
-
}
|
392 |
-
} else {
|
393 |
-
|
394 |
-
$style = 'post' == $this->object_type ? ' style="width:18%"' : '';
|
395 |
-
// $tag = 'side' !== $this->args( 'context' ) ? 'th' : 'p';
|
396 |
-
$tag = 'th';
|
397 |
-
printf( '<%1$s%2$s><label for="%3$s">%4$s</label></%1$s>', $tag, $style, $this->id(), $this->args( 'name' ) );
|
398 |
-
|
399 |
-
echo "\n\t<td>\n";
|
400 |
-
}
|
401 |
-
|
402 |
-
echo $this->args( 'before' );
|
403 |
-
|
404 |
-
$this_type = new cmb_Meta_Box_types( $this );
|
405 |
-
$this_type->render();
|
406 |
-
|
407 |
-
echo $this->args( 'after' );
|
408 |
-
|
409 |
-
echo "\n\t</td>\n</tr>";
|
410 |
-
}
|
411 |
-
|
412 |
-
/**
|
413 |
-
* Replaces a hash key - {#} - with the repeatable count
|
414 |
-
* @since 1.2.0
|
415 |
-
* @param string $value Value to update
|
416 |
-
* @return string Updated value
|
417 |
-
*/
|
418 |
-
public function replace_hash( $value ) {
|
419 |
-
// Replace hash with 1 based count
|
420 |
-
return str_ireplace( '{#}', ( $this->count() + 1 ), $value );
|
421 |
-
}
|
422 |
-
|
423 |
-
/**
|
424 |
-
* Fills in empty field parameters with defaults
|
425 |
-
* @since 1.1.0
|
426 |
-
* @param array $args Metabox field config array
|
427 |
-
*/
|
428 |
-
public function _set_field_defaults( $args ) {
|
429 |
-
|
430 |
-
// Set up blank or default values for empty ones
|
431 |
-
if ( ! isset( $args['name'] ) ) $args['name'] = '';
|
432 |
-
if ( ! isset( $args['desc'] ) ) $args['desc'] = '';
|
433 |
-
if ( ! isset( $args['before'] ) ) $args['before'] = '';
|
434 |
-
if ( ! isset( $args['after'] ) ) $args['after'] = '';
|
435 |
-
if ( ! isset( $args['protocols'] ) ) $args['protocols'] = null;
|
436 |
-
if ( ! isset( $args['description'] ) ) {
|
437 |
-
$args['description'] = isset( $args['desc'] ) ? $args['desc'] : '';
|
438 |
-
}
|
439 |
-
if ( ! isset( $args['default'] ) ) {
|
440 |
-
// Phase out 'std', and use 'default' instead
|
441 |
-
$args['default'] = isset( $args['std'] ) ? $args['std'] : '';
|
442 |
-
}
|
443 |
-
if ( ! isset( $args['preview_size'] ) ) $args['preview_size'] = array( 50, 50 );
|
444 |
-
if ( ! isset( $args['date_format'] ) ) $args['date_format'] = 'm\/d\/Y';
|
445 |
-
if ( ! isset( $args['time_format'] ) ) $args['time_format'] = 'h:i A';
|
446 |
-
// Allow a filter override of the default value
|
447 |
-
$args['default'] = apply_filters( 'cmb_default_filter', $args['default'], $args, $this->object_type, $this->object_type );
|
448 |
-
$args['allow'] = 'file' == $args['type'] && ! isset( $args['allow'] ) ? array( 'url', 'attachment' ) : array();
|
449 |
-
$args['save_id'] = 'file' == $args['type'] && ! ( isset( $args['save_id'] ) && ! $args['save_id'] );
|
450 |
-
// $args['multiple'] = isset( $args['multiple'] ) ? $args['multiple'] : ( 'multicheck' == $args['type'] ? true : false );
|
451 |
-
$args['multiple'] = isset( $args['multiple'] ) ? $args['multiple'] : false;
|
452 |
-
$args['repeatable'] = isset( $args['repeatable'] ) && $args['repeatable'] && ! $this->repeatable_exception( $args['type'] );
|
453 |
-
$args['inline'] = isset( $args['inline'] ) && $args['inline'] || false !== stripos( $args['type'], '_inline' );
|
454 |
-
$args['on_front'] = ! ( isset( $args['on_front'] ) && ! $args['on_front'] );
|
455 |
-
$args['attributes'] = isset( $args['attributes'] ) && is_array( $args['attributes'] ) ? $args['attributes'] : array();
|
456 |
-
$args['options'] = isset( $args['options'] ) && is_array( $args['options'] ) ? $args['options'] : array();
|
457 |
-
|
458 |
-
$args['options'] = 'group' == $args['type'] ? wp_parse_args( $args['options'], array(
|
459 |
-
'add_button' => __( 'Add Group', 'cmb' ),
|
460 |
-
'remove_button' => __( 'Remove Group', 'cmb' ),
|
461 |
-
) ) : $args['options'];
|
462 |
-
|
463 |
-
$args['_id'] = $args['id'];
|
464 |
-
$args['_name'] = $args['id'];
|
465 |
-
|
466 |
-
if ( $this->group ) {
|
467 |
-
$args['id'] = $this->group->args( 'id' ) .'_'. $this->group->args( 'count' ) .'_'. $args['id'];
|
468 |
-
$args['_name'] = $this->group->args( 'id' ) .'['. $this->group->args( 'count' ) .']['. $args['_name'] .']';
|
469 |
-
}
|
470 |
-
|
471 |
-
if ( 'wysiwyg' == $args['type'] ) {
|
472 |
-
$args['id'] = strtolower( str_ireplace( '-', '_', $args['id'] ) );
|
473 |
-
$args['options']['textarea_name'] = $args['_name'];
|
474 |
-
}
|
475 |
-
|
476 |
-
$option_types = array( 'taxonomy_select', 'taxonomy_radio', 'taxonomy_radio_inline' );
|
477 |
-
if ( in_array( $args['type'], $option_types, true ) ) {
|
478 |
-
|
479 |
-
// @todo implemention
|
480 |
-
$args['show_option_all'] = isset( $args['show_option_all'] ) && ! $args['show_option_all'] ? false : true;
|
481 |
-
$args['show_option_none'] = isset( $args['show_option_none'] ) && ! $args['show_option_none'] ? false : true;
|
482 |
-
|
483 |
-
}
|
484 |
-
|
485 |
-
return $args;
|
486 |
-
}
|
487 |
-
|
488 |
-
/**
|
489 |
-
* Updates attributes array values unless they exist from the field config array
|
490 |
-
* @since 1.1.0
|
491 |
-
* @param array $attrs Array of attributes to update
|
492 |
-
*/
|
493 |
-
public function maybe_set_attributes( $attrs = array() ) {
|
494 |
-
return wp_parse_args( $this->args['attributes'], $attrs );
|
495 |
-
}
|
496 |
-
|
497 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* CMB field class
|
5 |
+
* @since 1.1.0
|
6 |
+
*/
|
7 |
+
class cmb_Meta_Box_field {
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Metabox object id
|
11 |
+
* @var mixed
|
12 |
+
* @since 1.1.0
|
13 |
+
*/
|
14 |
+
public $object_id;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Metabox object type
|
18 |
+
* @var mixed
|
19 |
+
* @since 1.1.0
|
20 |
+
*/
|
21 |
+
public $object_type;
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Field arguments
|
25 |
+
* @var mixed
|
26 |
+
* @since 1.1.0
|
27 |
+
*/
|
28 |
+
public $args;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Field group object
|
32 |
+
* @var mixed
|
33 |
+
* @since 1.1.0
|
34 |
+
*/
|
35 |
+
public $group;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Field meta value
|
39 |
+
* @var mixed
|
40 |
+
* @since 1.1.0
|
41 |
+
*/
|
42 |
+
public $value;
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Constructs our field object
|
46 |
+
* @since 1.1.0
|
47 |
+
* @param array $field_args Field arguments
|
48 |
+
* @param array $group_field (optional) Group field object
|
49 |
+
*/
|
50 |
+
public function __construct( $field_args, $group_field = null ) {
|
51 |
+
$this->object_id = cmb_Meta_Box::get_object_id();
|
52 |
+
$this->object_type = cmb_Meta_Box::get_object_type();
|
53 |
+
$this->group = ! empty( $group_field ) ? $group_field : false;
|
54 |
+
$this->args = $this->_set_field_defaults( $field_args );
|
55 |
+
|
56 |
+
// Allow an override for the field's value
|
57 |
+
// (assuming no one would want to save 'cmb_no_override_val' as a value)
|
58 |
+
$this->value = apply_filters( 'cmb_override_meta_value', 'cmb_no_override_val', $this->object_id, $this->args(), $this->object_type, $this );
|
59 |
+
|
60 |
+
// If no override, get our meta
|
61 |
+
$this->value = 'cmb_no_override_val' === $this->value
|
62 |
+
? $this->get_data()
|
63 |
+
: $this->value;
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Non-existent methods fallback to checking for field arguments of the same name
|
68 |
+
* @since 1.1.0
|
69 |
+
* @param string $name Method name
|
70 |
+
* @param array $arguments Array of passed-in arguments
|
71 |
+
* @return mixed Value of field argument
|
72 |
+
*/
|
73 |
+
public function __call( $name, $arguments ) {
|
74 |
+
$key = isset( $arguments[0] ) ? $arguments[0] : false;
|
75 |
+
return $this->args( $name, $key );
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Retrieves the field id
|
80 |
+
* @since 1.1.0
|
81 |
+
* @param boolean $raw Whether to retrieve pre-modidifed id
|
82 |
+
* @return string Field id
|
83 |
+
*/
|
84 |
+
public function id( $raw = false ) {
|
85 |
+
$id = $raw ? '_id' : 'id';
|
86 |
+
return $this->args( $id );
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Get a field argument
|
91 |
+
* @since 1.1.0
|
92 |
+
* @param string $key Argument to check
|
93 |
+
* @param string $key Sub argument to check
|
94 |
+
* @return mixed Argument value or false if non-existent
|
95 |
+
*/
|
96 |
+
public function args( $key = '', $_key = '' ) {
|
97 |
+
$vars = $this->_data( 'args', $key );
|
98 |
+
if ( $_key ) {
|
99 |
+
return isset( $vars[ $_key ] ) ? $vars[ $_key ] : false;
|
100 |
+
}
|
101 |
+
return $vars;
|
102 |
+
}
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Get Field's value
|
106 |
+
* @since 1.1.0
|
107 |
+
* @param string $key If value is an array, is used to get array key->value
|
108 |
+
* @return mixed Field value or false if non-existent
|
109 |
+
*/
|
110 |
+
public function value( $key = '' ) {
|
111 |
+
return $this->_data( 'value', $key );
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Retrieve a portion of a field property
|
116 |
+
* @since 1.1.0
|
117 |
+
* @param string $var Field property to check
|
118 |
+
* @param string $key Field property array key to check
|
119 |
+
* @return mixed Queried property value or false
|
120 |
+
*/
|
121 |
+
public function _data( $var, $key = '' ) {
|
122 |
+
$vars = $this->$var;
|
123 |
+
if ( $key ) {
|
124 |
+
return isset( $vars[ $key ] ) ? $vars[ $key ] : false;
|
125 |
+
}
|
126 |
+
return $vars;
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Retrieves metadata/option data
|
131 |
+
* @since 1.0.1
|
132 |
+
* @param string $field_id Meta key/Option array key
|
133 |
+
* @return mixed Meta/Option value
|
134 |
+
*/
|
135 |
+
public function get_data( $field_id = '', $args = array() ) {
|
136 |
+
if ( $field_id ) {
|
137 |
+
$args['field_id'] = $field_id;
|
138 |
+
} else if ( $this->group ) {
|
139 |
+
$args['field_id'] = $this->group->id();
|
140 |
+
}
|
141 |
+
extract( $this->data_args( $args ) );
|
142 |
+
|
143 |
+
$data = 'options-page' === $type
|
144 |
+
? cmb_Meta_Box::get_option( $id, $field_id )
|
145 |
+
: get_metadata( $type, $id, $field_id, ( $single || $repeat ) /* If multicheck this can be multiple values */ );
|
146 |
+
|
147 |
+
if ( $this->group && $data ) {
|
148 |
+
$data = isset( $data[ $this->group->args( 'count' ) ][ $this->args( '_id' ) ] )
|
149 |
+
? $data[ $this->group->args( 'count' ) ][ $this->args( '_id' ) ]
|
150 |
+
: false;
|
151 |
+
}
|
152 |
+
return $data;
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Updates metadata/option data
|
157 |
+
* @since 1.0.1
|
158 |
+
* @param mixed $value Value to update data with
|
159 |
+
* @param bool $single Whether data is an array (add_metadata)
|
160 |
+
*/
|
161 |
+
public function update_data( $new_value, $single = true ) {
|
162 |
+
extract( $this->data_args( array( 'new_value' => $new_value, 'single' => $single ) ) );
|
163 |
+
|
164 |
+
$new_value = $repeat ? array_values( $new_value ) : $new_value;
|
165 |
+
|
166 |
+
if ( 'options-page' === $type )
|
167 |
+
return cmb_Meta_Box::update_option( $id, $field_id, $new_value, $single );
|
168 |
+
|
169 |
+
if ( ! $single )
|
170 |
+
return add_metadata( $type, $id, $field_id, $new_value, false );
|
171 |
+
|
172 |
+
return update_metadata( $type, $id, $field_id, $new_value );
|
173 |
+
}
|
174 |
+
|
175 |
+
/**
|
176 |
+
* Removes/updates metadata/option data
|
177 |
+
* @since 1.0.1
|
178 |
+
* @param string $old Old value
|
179 |
+
*/
|
180 |
+
public function remove_data( $old = '' ) {
|
181 |
+
extract( $this->data_args() );
|
182 |
+
|
183 |
+
return 'options-page' === $type
|
184 |
+
? cmb_Meta_Box::remove_option( $id, $field_id )
|
185 |
+
: delete_metadata( $type, $id, $field_id, $old );
|
186 |
+
}
|
187 |
+
|
188 |
+
/**
|
189 |
+
* data variables for get/set data methods
|
190 |
+
* @since 1.1.0
|
191 |
+
* @param array $args Override arguments
|
192 |
+
* @return array Updated arguments
|
193 |
+
*/
|
194 |
+
public function data_args( $args = array() ) {
|
195 |
+
$args = wp_parse_args( $args, array(
|
196 |
+
'type' => $this->object_type,
|
197 |
+
'id' => $this->object_id,
|
198 |
+
'field_id' => $this->id( true ),
|
199 |
+
'repeat' => $this->args( 'repeatable' ),
|
200 |
+
'single' => ! $this->args( 'multiple' ),
|
201 |
+
) );
|
202 |
+
return $args;
|
203 |
+
}
|
204 |
+
|
205 |
+
/**
|
206 |
+
* Checks if field has a registered validation callback
|
207 |
+
* @since 1.0.1
|
208 |
+
* @param mixed $meta_value Meta value
|
209 |
+
* @return mixed Possibly validated meta value
|
210 |
+
*/
|
211 |
+
public function sanitization_cb( $meta_value ) {
|
212 |
+
if ( empty( $meta_value ) )
|
213 |
+
return $meta_value;
|
214 |
+
|
215 |
+
// Check if the field has a registered validation callback
|
216 |
+
$cb = $this->maybe_callback( 'sanitization_cb' );
|
217 |
+
if ( false === $cb ) {
|
218 |
+
// If requestion NO validation, return meta value
|
219 |
+
return $meta_value;
|
220 |
+
} elseif ( $cb ) {
|
221 |
+
// Ok, callback is good, let's run it.
|
222 |
+
return call_user_func( $cb, $meta_value, $this->args(), $this );
|
223 |
+
}
|
224 |
+
|
225 |
+
$clean = new cmb_Meta_Box_Sanitize( $this, $meta_value );
|
226 |
+
// Validation via 'cmb_Meta_Box_Sanitize' (with fallback filter)
|
227 |
+
return $clean->{$this->type()}( $meta_value );
|
228 |
+
}
|
229 |
+
|
230 |
+
/**
|
231 |
+
* Checks if field has a callback value
|
232 |
+
* @since 1.0.1
|
233 |
+
* @param string $cb Callback string
|
234 |
+
* @return mixed NULL, false for NO validation, or $cb string if it exists.
|
235 |
+
*/
|
236 |
+
public function maybe_callback( $cb ) {
|
237 |
+
$field_args = $this->args();
|
238 |
+
if ( ! isset( $field_args[ $cb ] ) )
|
239 |
+
return;
|
240 |
+
|
241 |
+
// Check if metabox is requesting NO validation
|
242 |
+
$cb = false !== $field_args[ $cb ] && 'false' !== $field_args[ $cb ] ? $field_args[ $cb ] : false;
|
243 |
+
|
244 |
+
// If requestion NO validation, return false
|
245 |
+
if ( ! $cb )
|
246 |
+
return false;
|
247 |
+
|
248 |
+
if ( is_callable( $cb ) )
|
249 |
+
return $cb;
|
250 |
+
}
|
251 |
+
|
252 |
+
/**
|
253 |
+
* Determine if current type is excempt from escaping
|
254 |
+
* @since 1.1.0
|
255 |
+
* @return bool True if exempt
|
256 |
+
*/
|
257 |
+
public function escaping_exception() {
|
258 |
+
// These types cannot be escaped
|
259 |
+
return in_array( $this->type(), array(
|
260 |
+
'file_list',
|
261 |
+
'multicheck',
|
262 |
+
'text_datetime_timestamp_timezone',
|
263 |
+
) );
|
264 |
+
}
|
265 |
+
|
266 |
+
/**
|
267 |
+
* Determine if current type cannot be repeatable
|
268 |
+
* @since 1.1.0
|
269 |
+
* @param string $type Field type to check
|
270 |
+
* @return bool True if type cannot be repeatable
|
271 |
+
*/
|
272 |
+
public function repeatable_exception( $type ) {
|
273 |
+
// These types cannot be escaped
|
274 |
+
return in_array( $type, array(
|
275 |
+
'file', // Use file_list
|
276 |
+
'radio',
|
277 |
+
'title',
|
278 |
+
'group',
|
279 |
+
// @todo Ajax load wp_editor: http://wordpress.stackexchange.com/questions/51776/how-to-load-wp-editor-through-ajax-jquery
|
280 |
+
'wysiwyg',
|
281 |
+
'checkbox',
|
282 |
+
'radio_inline',
|
283 |
+
'taxonomy_radio',
|
284 |
+
'taxonomy_select',
|
285 |
+
'taxonomy_multicheck',
|
286 |
+
) );
|
287 |
+
}
|
288 |
+
|
289 |
+
/**
|
290 |
+
* Escape the value before output. Defaults to 'esc_attr()'
|
291 |
+
* @since 1.0.1
|
292 |
+
* @param mixed $meta_value Meta value
|
293 |
+
* @param mixed $func Escaping function (if not esc_attr())
|
294 |
+
* @return mixed Final value
|
295 |
+
*/
|
296 |
+
public function escaped_value( $func = 'esc_attr', $meta_value = '' ) {
|
297 |
+
|
298 |
+
if ( isset( $this->escaped_value ) )
|
299 |
+
return $this->escaped_value;
|
300 |
+
|
301 |
+
$meta_value = $meta_value ? $meta_value : $this->value();
|
302 |
+
// Check if the field has a registered escaping callback
|
303 |
+
$cb = $this->maybe_callback( 'escape_cb' );
|
304 |
+
if ( false === $cb || $this->escaping_exception() ) {
|
305 |
+
// If requesting NO escaping, return meta value
|
306 |
+
return ! empty( $meta_value ) ? $meta_value : $this->args( 'default' );
|
307 |
+
} elseif ( $cb ) {
|
308 |
+
// Ok, callback is good, let's run it.
|
309 |
+
return call_user_func( $cb, $meta_value, $this->args(), $this );
|
310 |
+
}
|
311 |
+
|
312 |
+
// Or custom escaping filter can be used
|
313 |
+
$esc = apply_filters( 'cmb_types_esc_'. $this->type(), null, $meta_value, $this->args(), $this );
|
314 |
+
if ( null !== $esc ) {
|
315 |
+
return $esc;
|
316 |
+
}
|
317 |
+
|
318 |
+
// escaping function passed in?
|
319 |
+
$func = $func ? $func : 'esc_attr';
|
320 |
+
$meta_value = ! empty( $meta_value ) ? $meta_value : $this->args( 'default' );
|
321 |
+
|
322 |
+
if ( is_array( $meta_value ) ) {
|
323 |
+
foreach ( $meta_value as $key => $value ) {
|
324 |
+
$meta_value[ $key ] = call_user_func( $func, $value );
|
325 |
+
}
|
326 |
+
} else {
|
327 |
+
$meta_value = call_user_func( $func, $meta_value );
|
328 |
+
}
|
329 |
+
|
330 |
+
$this->escaped_value = $meta_value;
|
331 |
+
return $this->escaped_value;
|
332 |
+
}
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Offset a time value based on timezone
|
336 |
+
* @since 1.0.0
|
337 |
+
* @return string Offset time string
|
338 |
+
*/
|
339 |
+
public function field_timezone_offset() {
|
340 |
+
return cmb_Meta_Box::timezone_offset( $this->field_timezone() );
|
341 |
+
}
|
342 |
+
|
343 |
+
/**
|
344 |
+
* Return timezone string
|
345 |
+
* @since 1.0.0
|
346 |
+
* @return string Timezone string
|
347 |
+
*/
|
348 |
+
public function field_timezone() {
|
349 |
+
|
350 |
+
// Is timezone arg set?
|
351 |
+
if ( $this->args( 'timezone' ) ) {
|
352 |
+
return $this->args( 'timezone' ) ;
|
353 |
+
}
|
354 |
+
// Is there another meta key with a timezone stored as its value we should use?
|
355 |
+
else if ( $this->args( 'timezone_meta_key' ) ) {
|
356 |
+
return $this->get_data( $this->args( 'timezone_meta_key' ) );
|
357 |
+
}
|
358 |
+
|
359 |
+
return false;
|
360 |
+
}
|
361 |
+
|
362 |
+
/**
|
363 |
+
* Render a field row
|
364 |
+
* @since 1.0.0
|
365 |
+
*/
|
366 |
+
public function render_field() {
|
367 |
+
|
368 |
+
// If field is requesting to not be shown on the front-end
|
369 |
+
if ( ! is_admin() && ! $this->args( 'on_front' ) )
|
370 |
+
return;
|
371 |
+
|
372 |
+
// If field is requesting to be conditionally shown
|
373 |
+
if ( is_callable( $this->args( 'show_on_cb' ) ) && ! call_user_func( $this->args( 'show_on_cb' ), $this ) )
|
374 |
+
return;
|
375 |
+
|
376 |
+
$classes = 'cmb-type-'. sanitize_html_class( $this->type() );
|
377 |
+
$classes .= ' cmb_id_'. sanitize_html_class( $this->id() );
|
378 |
+
$classes .= $this->args( 'repeatable' ) ? ' cmb-repeat' : '';
|
379 |
+
// 'inline' flag, or _inline in the field type, set to true
|
380 |
+
$classes .= $this->args( 'inline' ) ? ' cmb-inline' : '';
|
381 |
+
$is_side = 'side' === $this->args( 'context' );
|
382 |
+
|
383 |
+
printf( "<tr class=\"%s\">\n", $classes );
|
384 |
+
|
385 |
+
if ( 'title' == $this->type() || ! $this->args( 'show_names' ) || $is_side ) {
|
386 |
+
echo "\t<td colspan=\"2\">\n";
|
387 |
+
|
388 |
+
if ( ! $this->args( 'show_names' ) || $is_side ) {
|
389 |
+
$style = ! $is_side || 'title' == $this->type() ? ' style="display:none;"' : '';
|
390 |
+
printf( "\n<label%s for=\"%s\">%s</label>\n", $style, $this->id(), $this->args( 'name' ) );
|
391 |
+
}
|
392 |
+
} else {
|
393 |
+
|
394 |
+
$style = 'post' == $this->object_type ? ' style="width:18%"' : '';
|
395 |
+
// $tag = 'side' !== $this->args( 'context' ) ? 'th' : 'p';
|
396 |
+
$tag = 'th';
|
397 |
+
printf( '<%1$s%2$s><label for="%3$s">%4$s</label></%1$s>', $tag, $style, $this->id(), $this->args( 'name' ) );
|
398 |
+
|
399 |
+
echo "\n\t<td>\n";
|
400 |
+
}
|
401 |
+
|
402 |
+
echo $this->args( 'before' );
|
403 |
+
|
404 |
+
$this_type = new cmb_Meta_Box_types( $this );
|
405 |
+
$this_type->render();
|
406 |
+
|
407 |
+
echo $this->args( 'after' );
|
408 |
+
|
409 |
+
echo "\n\t</td>\n</tr>";
|
410 |
+
}
|
411 |
+
|
412 |
+
/**
|
413 |
+
* Replaces a hash key - {#} - with the repeatable count
|
414 |
+
* @since 1.2.0
|
415 |
+
* @param string $value Value to update
|
416 |
+
* @return string Updated value
|
417 |
+
*/
|
418 |
+
public function replace_hash( $value ) {
|
419 |
+
// Replace hash with 1 based count
|
420 |
+
return str_ireplace( '{#}', ( $this->count() + 1 ), $value );
|
421 |
+
}
|
422 |
+
|
423 |
+
/**
|
424 |
+
* Fills in empty field parameters with defaults
|
425 |
+
* @since 1.1.0
|
426 |
+
* @param array $args Metabox field config array
|
427 |
+
*/
|
428 |
+
public function _set_field_defaults( $args ) {
|
429 |
+
|
430 |
+
// Set up blank or default values for empty ones
|
431 |
+
if ( ! isset( $args['name'] ) ) $args['name'] = '';
|
432 |
+
if ( ! isset( $args['desc'] ) ) $args['desc'] = '';
|
433 |
+
if ( ! isset( $args['before'] ) ) $args['before'] = '';
|
434 |
+
if ( ! isset( $args['after'] ) ) $args['after'] = '';
|
435 |
+
if ( ! isset( $args['protocols'] ) ) $args['protocols'] = null;
|
436 |
+
if ( ! isset( $args['description'] ) ) {
|
437 |
+
$args['description'] = isset( $args['desc'] ) ? $args['desc'] : '';
|
438 |
+
}
|
439 |
+
if ( ! isset( $args['default'] ) ) {
|
440 |
+
// Phase out 'std', and use 'default' instead
|
441 |
+
$args['default'] = isset( $args['std'] ) ? $args['std'] : '';
|
442 |
+
}
|
443 |
+
if ( ! isset( $args['preview_size'] ) ) $args['preview_size'] = array( 50, 50 );
|
444 |
+
if ( ! isset( $args['date_format'] ) ) $args['date_format'] = 'm\/d\/Y';
|
445 |
+
if ( ! isset( $args['time_format'] ) ) $args['time_format'] = 'h:i A';
|
446 |
+
// Allow a filter override of the default value
|
447 |
+
$args['default'] = apply_filters( 'cmb_default_filter', $args['default'], $args, $this->object_type, $this->object_type );
|
448 |
+
$args['allow'] = 'file' == $args['type'] && ! isset( $args['allow'] ) ? array( 'url', 'attachment' ) : array();
|
449 |
+
$args['save_id'] = 'file' == $args['type'] && ! ( isset( $args['save_id'] ) && ! $args['save_id'] );
|
450 |
+
// $args['multiple'] = isset( $args['multiple'] ) ? $args['multiple'] : ( 'multicheck' == $args['type'] ? true : false );
|
451 |
+
$args['multiple'] = isset( $args['multiple'] ) ? $args['multiple'] : false;
|
452 |
+
$args['repeatable'] = isset( $args['repeatable'] ) && $args['repeatable'] && ! $this->repeatable_exception( $args['type'] );
|
453 |
+
$args['inline'] = isset( $args['inline'] ) && $args['inline'] || false !== stripos( $args['type'], '_inline' );
|
454 |
+
$args['on_front'] = ! ( isset( $args['on_front'] ) && ! $args['on_front'] );
|
455 |
+
$args['attributes'] = isset( $args['attributes'] ) && is_array( $args['attributes'] ) ? $args['attributes'] : array();
|
456 |
+
$args['options'] = isset( $args['options'] ) && is_array( $args['options'] ) ? $args['options'] : array();
|
457 |
+
|
458 |
+
$args['options'] = 'group' == $args['type'] ? wp_parse_args( $args['options'], array(
|
459 |
+
'add_button' => __( 'Add Group', 'cmb' ),
|
460 |
+
'remove_button' => __( 'Remove Group', 'cmb' ),
|
461 |
+
) ) : $args['options'];
|
462 |
+
|
463 |
+
$args['_id'] = $args['id'];
|
464 |
+
$args['_name'] = $args['id'];
|
465 |
+
|
466 |
+
if ( $this->group ) {
|
467 |
+
$args['id'] = $this->group->args( 'id' ) .'_'. $this->group->args( 'count' ) .'_'. $args['id'];
|
468 |
+
$args['_name'] = $this->group->args( 'id' ) .'['. $this->group->args( 'count' ) .']['. $args['_name'] .']';
|
469 |
+
}
|
470 |
+
|
471 |
+
if ( 'wysiwyg' == $args['type'] ) {
|
472 |
+
$args['id'] = strtolower( str_ireplace( '-', '_', $args['id'] ) );
|
473 |
+
$args['options']['textarea_name'] = $args['_name'];
|
474 |
+
}
|
475 |
+
|
476 |
+
$option_types = array( 'taxonomy_select', 'taxonomy_radio', 'taxonomy_radio_inline' );
|
477 |
+
if ( in_array( $args['type'], $option_types, true ) ) {
|
478 |
+
|
479 |
+
// @todo implemention
|
480 |
+
$args['show_option_all'] = isset( $args['show_option_all'] ) && ! $args['show_option_all'] ? false : true;
|
481 |
+
$args['show_option_none'] = isset( $args['show_option_none'] ) && ! $args['show_option_none'] ? false : true;
|
482 |
+
|
483 |
+
}
|
484 |
+
|
485 |
+
return $args;
|
486 |
+
}
|
487 |
+
|
488 |
+
/**
|
489 |
+
* Updates attributes array values unless they exist from the field config array
|
490 |
+
* @since 1.1.0
|
491 |
+
* @param array $attrs Array of attributes to update
|
492 |
+
*/
|
493 |
+
public function maybe_set_attributes( $attrs = array() ) {
|
494 |
+
return wp_parse_args( $this->args['attributes'], $attrs );
|
495 |
+
}
|
496 |
+
|
497 |
+
}
|
lib/cmb_metaboxes/helpers/cmb_Meta_Box_types.php
CHANGED
@@ -1,794 +1,794 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* CMB field types
|
5 |
-
*
|
6 |
-
* @todo test taxonomy methods with non-post objects
|
7 |
-
* @todo test all methods with non-post objects
|
8 |
-
* @todo Date/Time fields should store date format as data attribute for JS
|
9 |
-
*
|
10 |
-
* @since 1.0.0
|
11 |
-
*/
|
12 |
-
class cmb_Meta_Box_types {
|
13 |
-
|
14 |
-
/**
|
15 |
-
* An iterator value for repeatable fields
|
16 |
-
* @var integer
|
17 |
-
* @since 1.0.0
|
18 |
-
*/
|
19 |
-
public $iterator = 0;
|
20 |
-
|
21 |
-
/**
|
22 |
-
* Current field
|
23 |
-
* @var array
|
24 |
-
* @since 1.0.0
|
25 |
-
*/
|
26 |
-
public $field;
|
27 |
-
|
28 |
-
public function __construct( $field ) {
|
29 |
-
$this->field = $field;
|
30 |
-
}
|
31 |
-
|
32 |
-
/**
|
33 |
-
* Default fallback. Allows rendering fields via "cmb_render_$name" hook
|
34 |
-
* @since 1.0.0
|
35 |
-
* @param string $name Non-existent method name
|
36 |
-
* @param array $arguments All arguments passed to the method
|
37 |
-
*/
|
38 |
-
public function __call( $name, $arguments ) {
|
39 |
-
// When a non-registered field is called, send it through an action.
|
40 |
-
do_action( "cmb_render_$name", $this->field->args(), $this->field->escaped_value(), $this->field->object_id, $this->field->object_type, $this );
|
41 |
-
}
|
42 |
-
|
43 |
-
/**
|
44 |
-
* Render a field (and handle repeatable)
|
45 |
-
* @since 1.1.0
|
46 |
-
*/
|
47 |
-
public function render() {
|
48 |
-
if ( $this->field->args( 'repeatable' ) ) {
|
49 |
-
$this->render_repeatable_field();
|
50 |
-
} else {
|
51 |
-
$this->_render();
|
52 |
-
}
|
53 |
-
}
|
54 |
-
|
55 |
-
/**
|
56 |
-
* Render a field type
|
57 |
-
* @since 1.1.0
|
58 |
-
*/
|
59 |
-
protected function _render() {
|
60 |
-
echo $this->{$this->field->type()}();
|
61 |
-
}
|
62 |
-
|
63 |
-
/**
|
64 |
-
* Checks if we can get a post object, and if so, uses `get_the_terms` which utilizes caching
|
65 |
-
* @since 1.0.2
|
66 |
-
* @return mixed Array of terms on success
|
67 |
-
*/
|
68 |
-
public function get_object_terms() {
|
69 |
-
$object_id = $this->field->object_id;
|
70 |
-
$taxonomy = $this->field->args( 'taxonomy' );
|
71 |
-
|
72 |
-
if ( ! $post = get_post( $object_id ) ) {
|
73 |
-
|
74 |
-
$cache_key = 'cmb-cache-'. $taxonomy .'-'. $object_id;
|
75 |
-
|
76 |
-
// Check cache
|
77 |
-
$cached = $test = get_transient( $cache_key );
|
78 |
-
if ( $cached )
|
79 |
-
return $cached;
|
80 |
-
|
81 |
-
$cached = wp_get_object_terms( $object_id, $taxonomy );
|
82 |
-
// Do our own (minimal) caching. Long enough for a page-load.
|
83 |
-
$set = set_transient( $cache_key, $cached, 60 );
|
84 |
-
return $cached;
|
85 |
-
}
|
86 |
-
|
87 |
-
// WP caches internally so it's better to use
|
88 |
-
return get_the_terms( $post, $taxonomy );
|
89 |
-
|
90 |
-
}
|
91 |
-
|
92 |
-
/**
|
93 |
-
* Determine a file's extension
|
94 |
-
* @since 1.0.0
|
95 |
-
* @param string $file File url
|
96 |
-
* @return string|false File extension or false
|
97 |
-
*/
|
98 |
-
public function get_file_ext( $file ) {
|
99 |
-
$parsed = @parse_url( $file, PHP_URL_PATH );
|
100 |
-
return $parsed ? strtolower( pathinfo( $parsed, PATHINFO_EXTENSION ) ) : false;
|
101 |
-
}
|
102 |
-
|
103 |
-
/**
|
104 |
-
* Determines if a file has a valid image extension
|
105 |
-
* @since 1.0.0
|
106 |
-
* @param string $file File url
|
107 |
-
* @return bool Whether file has a valid image extension
|
108 |
-
*/
|
109 |
-
public function is_valid_img_ext( $file ) {
|
110 |
-
$file_ext = $this->get_file_ext( $file );
|
111 |
-
|
112 |
-
$this->valid = empty( $this->valid )
|
113 |
-
? (array) apply_filters( 'cmb_valid_img_types', array( 'jpg', 'jpeg', 'png', 'gif', 'ico', 'icon' ) )
|
114 |
-
: $this->valid;
|
115 |
-
|
116 |
-
return ( $file_ext && in_array( $file_ext, $this->valid ) );
|
117 |
-
}
|
118 |
-
|
119 |
-
/**
|
120 |
-
* Handles parsing and filtering attributes while preserving any passed in via field config.
|
121 |
-
* @since 1.1.0
|
122 |
-
* @param array $args Override arguments
|
123 |
-
* @param string $element Element for filter
|
124 |
-
* @param array $defaults Default arguments
|
125 |
-
* @return array Parsed and filtered arguments
|
126 |
-
*/
|
127 |
-
public function parse_args( $args, $element, $defaults ) {
|
128 |
-
return wp_parse_args( apply_filters( "cmb_{$element}_attributes", $this->field->maybe_set_attributes( $args ), $this->field, $this ), $defaults );
|
129 |
-
}
|
130 |
-
|
131 |
-
/**
|
132 |
-
* Combines attributes into a string for a form element
|
133 |
-
* @since 1.1.0
|
134 |
-
* @param array $attrs Attributes to concatenate
|
135 |
-
* @param array $attr_exclude Attributes that should NOT be concatenated
|
136 |
-
* @return string String of attributes for form element
|
137 |
-
*/
|
138 |
-
public function concat_attrs( $attrs, $attr_exclude = array() ) {
|
139 |
-
$attributes = '';
|
140 |
-
foreach ( $attrs as $attr => $val ) {
|
141 |
-
if ( ! in_array( $attr, (array) $attr_exclude, true ) )
|
142 |
-
$attributes .= sprintf( ' %s="%s"', $attr, $val );
|
143 |
-
}
|
144 |
-
return $attributes;
|
145 |
-
}
|
146 |
-
|
147 |
-
/**
|
148 |
-
* Generates html for an option element
|
149 |
-
* @since 1.1.0
|
150 |
-
* @param string $opt_label Option label
|
151 |
-
* @param string $opt_value Option value
|
152 |
-
* @param mixed $selected Selected attribute if option is selected
|
153 |
-
* @return string Generated option element html
|
154 |
-
*/
|
155 |
-
public function option( $opt_label, $opt_value, $selected ) {
|
156 |
-
return sprintf( "\t".'<option value="%s" %s>%s</option>', $opt_value, selected( $selected, true, false ), $opt_label )."\n";
|
157 |
-
}
|
158 |
-
|
159 |
-
/**
|
160 |
-
* Generates options html
|
161 |
-
* @since 1.1.0
|
162 |
-
* @param array $args Optional arguments
|
163 |
-
* @param string $method Method to generate individual option item
|
164 |
-
* @return string Concatenated html options
|
165 |
-
*/
|
166 |
-
public function concat_options( $args = array(), $method = 'list_input' ) {
|
167 |
-
|
168 |
-
$options = (array) $this->field->args( 'options' );
|
169 |
-
$saved_value = $this->field->escaped_value();
|
170 |
-
$value = $saved_value ? $saved_value : $this->field->args( 'default' );
|
171 |
-
|
172 |
-
$_options = ''; $i = 1;
|
173 |
-
foreach ( $options as $option_key => $option ) {
|
174 |
-
|
175 |
-
// Check for the "old" way
|
176 |
-
$opt_label = is_array( $option ) && array_key_exists( 'name', $option ) ? $option['name'] : $option;
|
177 |
-
$opt_value = is_array( $option ) && array_key_exists( 'value', $option ) ? $option['value'] : $option_key;
|
178 |
-
// Check if this option is the value of the input
|
179 |
-
$is_current = $value == $opt_value;
|
180 |
-
|
181 |
-
if ( ! empty( $args ) ) {
|
182 |
-
// Clone args & modify for just this item
|
183 |
-
$this_args = $args;
|
184 |
-
$this_args['value'] = $opt_value;
|
185 |
-
$this_args['label'] = $opt_label;
|
186 |
-
if ( $is_current )
|
187 |
-
$this_args['checked'] = 'checked';
|
188 |
-
|
189 |
-
$_options .= $this->$method( $this_args, $i );
|
190 |
-
} else {
|
191 |
-
$_options .= $this->option( $opt_label, $opt_value, $is_current );
|
192 |
-
}
|
193 |
-
$i++;
|
194 |
-
}
|
195 |
-
return $_options;
|
196 |
-
}
|
197 |
-
|
198 |
-
/**
|
199 |
-
* Generates html for list item with input
|
200 |
-
* @since 1.1.0
|
201 |
-
* @param array $args Override arguments
|
202 |
-
* @param int $i Iterator value
|
203 |
-
* @return string Gnerated list item html
|
204 |
-
*/
|
205 |
-
public function list_input( $args = array(), $i ) {
|
206 |
-
$args = $this->parse_args( $args, 'list_input', array(
|
207 |
-
'type' => 'radio',
|
208 |
-
'class' => 'cmb_option',
|
209 |
-
'name' => $this->_name(),
|
210 |
-
'id' => $this->_id( $i ),
|
211 |
-
'value' => $this->field->escaped_value(),
|
212 |
-
'label' => '',
|
213 |
-
) );
|
214 |
-
|
215 |
-
return sprintf( "\t".'<li><input%s/> <label for="%s">%s</label></li>'."\n", $this->concat_attrs( $args, 'label' ), $args['id'], $args['label'] );
|
216 |
-
}
|
217 |
-
|
218 |
-
/**
|
219 |
-
* Generates html for list item with checkbox input
|
220 |
-
* @since 1.1.0
|
221 |
-
* @param array $args Override arguments
|
222 |
-
* @param int $i Iterator value
|
223 |
-
* @return string Gnerated list item html
|
224 |
-
*/
|
225 |
-
public function list_input_checkbox( $args, $i ) {
|
226 |
-
unset( $args['selected'] );
|
227 |
-
$saved_value = $this->field->escaped_value();
|
228 |
-
if ( is_array( $saved_value ) && in_array( $args['value'], $saved_value ) ) {
|
229 |
-
$args['checked'] = 'checked';
|
230 |
-
}
|
231 |
-
return $this->list_input( $args, $i );
|
232 |
-
}
|
233 |
-
|
234 |
-
/**
|
235 |
-
* Generates repeatable field table markup
|
236 |
-
* @since 1.0.0
|
237 |
-
*/
|
238 |
-
public function render_repeatable_field() {
|
239 |
-
$table_id = $this->field->id() .'_repeat';
|
240 |
-
|
241 |
-
$this->_desc( true, true );
|
242 |
-
?>
|
243 |
-
|
244 |
-
<table id="<?php echo $table_id; ?>" class="cmb-repeat-table">
|
245 |
-
<tbody>
|
246 |
-
<?php $this->repeatable_rows(); ?>
|
247 |
-
</tbody>
|
248 |
-
</table>
|
249 |
-
<p class="add-row">
|
250 |
-
<a data-selector="<?php echo $table_id; ?>" class="add-row-button button" href="#"><?php _e( 'Add Row', 'cmb' ); ?></a>
|
251 |
-
</p>
|
252 |
-
|
253 |
-
<?php
|
254 |
-
// reset iterator
|
255 |
-
$this->iterator = 0;
|
256 |
-
}
|
257 |
-
|
258 |
-
/**
|
259 |
-
* Generates repeatable field rows
|
260 |
-
* @since 1.1.0
|
261 |
-
*/
|
262 |
-
public function repeatable_rows() {
|
263 |
-
$meta_value = $this->field->escaped_value();
|
264 |
-
// check for default content
|
265 |
-
$default = $this->field->args( 'default' );
|
266 |
-
|
267 |
-
// check for saved data
|
268 |
-
if ( ! empty( $meta_value ) ) {
|
269 |
-
$meta_value = is_array( $meta_value ) ? array_filter( $meta_value ) : $meta_value;
|
270 |
-
$meta_value = ! empty( $meta_value ) ? $meta_value : $default;
|
271 |
-
} else {
|
272 |
-
$meta_value = $default;
|
273 |
-
}
|
274 |
-
|
275 |
-
// Loop value array and add a row
|
276 |
-
if ( ! empty( $meta_value ) ) {
|
277 |
-
foreach ( (array) $meta_value as $val ) {
|
278 |
-
$this->field->escaped_value = $val;
|
279 |
-
$this->repeat_row();
|
280 |
-
$this->iterator++;
|
281 |
-
}
|
282 |
-
} else {
|
283 |
-
// Otherwise add one row
|
284 |
-
$this->repeat_row();
|
285 |
-
}
|
286 |
-
|
287 |
-
// Then add an empty row
|
288 |
-
$this->field->escaped_value = '';
|
289 |
-
$this->iterator = $this->iterator ? $this->iterator : 1;
|
290 |
-
$this->repeat_row( 'empty-row' );
|
291 |
-
}
|
292 |
-
|
293 |
-
/**
|
294 |
-
* Generates a repeatable row's markup
|
295 |
-
* @since 1.1.0
|
296 |
-
* @param string $class Repeatable table row's class
|
297 |
-
*/
|
298 |
-
protected function repeat_row( $class = 'repeat-row' ) {
|
299 |
-
?>
|
300 |
-
|
301 |
-
<tr class="<?php echo $class; ?>">
|
302 |
-
<td>
|
303 |
-
<?php $this->_render(); ?>
|
304 |
-
</td>
|
305 |
-
<td class="remove-row">
|
306 |
-
<a class="button remove-row-button" href="#"><?php _e( 'Remove', 'cmb' ); ?></a>
|
307 |
-
</td>
|
308 |
-
</tr>
|
309 |
-
|
310 |
-
<?php
|
311 |
-
}
|
312 |
-
|
313 |
-
/**
|
314 |
-
* Generates description markup
|
315 |
-
* @since 1.0.0
|
316 |
-
* @param boolean $paragraph Paragraph tag or span
|
317 |
-
* @param boolean $echo Whether to echo description or only return it
|
318 |
-
* @return string Field's description markup
|
319 |
-
*/
|
320 |
-
public function _desc( $paragraph = false, $echo = false ) {
|
321 |
-
// Prevent description from printing multiple times for repeatable fields
|
322 |
-
if ( $this->field->args( 'repeatable' ) || $this->iterator > 0 ) {
|
323 |
-
return '';
|
324 |
-
}
|
325 |
-
$tag = $paragraph ? 'p' : 'span';
|
326 |
-
$desc = "\n<$tag class=\"cmb_metabox_description\">{$this->field->args( 'description' )}</$tag>\n";
|
327 |
-
if ( $echo )
|
328 |
-
echo $desc;
|
329 |
-
return $desc;
|
330 |
-
}
|
331 |
-
|
332 |
-
/**
|
333 |
-
* Generate field name attribute
|
334 |
-
* @since 1.1.0
|
335 |
-
* @param string $suffix For multi-part fields
|
336 |
-
* @return string Name attribute
|
337 |
-
*/
|
338 |
-
public function _name( $suffix = '' ) {
|
339 |
-
return $this->field->args( '_name' ) . ( $this->field->args( 'repeatable' ) ? '['. $this->iterator .']' : '' ) . $suffix;
|
340 |
-
}
|
341 |
-
|
342 |
-
/**
|
343 |
-
* Generate field id attribute
|
344 |
-
* @since 1.1.0
|
345 |
-
* @param string $suffix For multi-part fields
|
346 |
-
* @return string Id attribute
|
347 |
-
*/
|
348 |
-
public function _id( $suffix = '' ) {
|
349 |
-
return $this->field->id() . $suffix . ( $this->field->args( 'repeatable' ) ? '_'. $this->iterator .'" data-iterator="'. $this->iterator : '' );
|
350 |
-
}
|
351 |
-
|
352 |
-
/**
|
353 |
-
* Handles outputting an 'input' element
|
354 |
-
* @since 1.1.0
|
355 |
-
* @param array $args Override arguments
|
356 |
-
* @return string Form input element
|
357 |
-
*/
|
358 |
-
public function input( $args = array() ) {
|
359 |
-
$args = $this->parse_args( $args, 'input', array(
|
360 |
-
'type' => 'text',
|
361 |
-
'class' => 'regular-text',
|
362 |
-
'name' => $this->_name(),
|
363 |
-
'id' => $this->_id(),
|
364 |
-
'value' => $this->field->escaped_value(),
|
365 |
-
'desc' => $this->_desc( true ),
|
366 |
-
) );
|
367 |
-
|
368 |
-
return sprintf( '<input%s/>%s', $this->concat_attrs( $args, 'desc' ), $args['desc'] );
|
369 |
-
}
|
370 |
-
|
371 |
-
/**
|
372 |
-
* Handles outputting an 'textarea' element
|
373 |
-
* @since 1.1.0
|
374 |
-
* @param array $args Override arguments
|
375 |
-
* @return string Form textarea element
|
376 |
-
*/
|
377 |
-
public function textarea( $args = array() ) {
|
378 |
-
$args = $this->parse_args( $args, 'textarea', array(
|
379 |
-
'class' => 'cmb_textarea',
|
380 |
-
'name' => $this->_name(),
|
381 |
-
'id' => $this->_id(),
|
382 |
-
'cols' => 60,
|
383 |
-
'rows' => 10,
|
384 |
-
'value' => $this->field->escaped_value( 'esc_textarea' ),
|
385 |
-
'desc' => $this->_desc( true ),
|
386 |
-
) );
|
387 |
-
return sprintf( '<textarea%s>%s</textarea>%s', $this->concat_attrs( $args, array( 'desc', 'value' ) ), $args['value'], $args['desc'] );
|
388 |
-
}
|
389 |
-
|
390 |
-
/**
|
391 |
-
* Begin Field Types
|
392 |
-
*/
|
393 |
-
|
394 |
-
public function text() {
|
395 |
-
return $this->input();
|
396 |
-
}
|
397 |
-
|
398 |
-
public function text_small() {
|
399 |
-
return $this->input( array( 'class' => 'cmb_text_small', 'desc' => $this->_desc() ) );
|
400 |
-
}
|
401 |
-
|
402 |
-
public function text_medium() {
|
403 |
-
return $this->input( array( 'class' => 'cmb_text_medium', 'desc' => $this->_desc() ) );
|
404 |
-
}
|
405 |
-
|
406 |
-
public function text_email() {
|
407 |
-
return $this->input( array( 'class' => 'cmb_text_email cmb_text_medium', 'type' => 'email' ) );
|
408 |
-
}
|
409 |
-
|
410 |
-
public function text_url() {
|
411 |
-
return $this->input( array( 'class' => 'cmb_text_url cmb_text_medium regular-text', 'value' => $this->field->escaped_value( 'esc_url' ) ) );
|
412 |
-
}
|
413 |
-
|
414 |
-
public function text_date() {
|
415 |
-
return $this->input( array( 'class' => 'cmb_text_small cmb_datepicker', 'desc' => $this->_desc() ) );
|
416 |
-
}
|
417 |
-
|
418 |
-
public function text_time() {
|
419 |
-
return $this->input( array( 'class' => 'cmb_timepicker text_time', 'desc' => $this->_desc() ) );
|
420 |
-
}
|
421 |
-
|
422 |
-
public function text_money() {
|
423 |
-
return ( ! $this->field->args( 'before' ) ? '$ ' : ' ' ) . $this->input( array( 'class' => 'cmb_text_money', 'desc' => $this->_desc() ) );
|
424 |
-
}
|
425 |
-
|
426 |
-
public function textarea_small() {
|
427 |
-
return $this->textarea( array( 'class' => 'cmb_textarea_small', 'rows' => 4 ) );
|
428 |
-
}
|
429 |
-
|
430 |
-
public function textarea_code() {
|
431 |
-
return sprintf( '<pre>%s</pre>', $this->textarea( array( 'class' => 'cmb_textarea_code' ) ) );
|
432 |
-
}
|
433 |
-
|
434 |
-
public function wysiwyg( $args = array() ) {
|
435 |
-
extract( $this->parse_args( $args, 'input', array(
|
436 |
-
'id' => $this->_id(),
|
437 |
-
'value' => $this->field->escaped_value( 'stripslashes' ),
|
438 |
-
'desc' => $this->_desc( true ),
|
439 |
-
'options' => $this->field->args( 'options' ),
|
440 |
-
) ) );
|
441 |
-
|
442 |
-
wp_editor( $value, $id, $options );
|
443 |
-
echo $desc;
|
444 |
-
}
|
445 |
-
|
446 |
-
public function text_date_timestamp() {
|
447 |
-
$meta_value = $this->field->escaped_value();
|
448 |
-
$value = ! empty( $meta_value ) ? date( $this->field->args( 'date_format' ), $meta_value ) : '';
|
449 |
-
return $this->input( array( 'class' => 'cmb_text_small cmb_datepicker', 'value' => $value ) );
|
450 |
-
}
|
451 |
-
|
452 |
-
public function text_datetime_timestamp( $meta_value = '' ) {
|
453 |
-
$desc = '';
|
454 |
-
if ( ! $meta_value ) {
|
455 |
-
$meta_value = $this->field->escaped_value();
|
456 |
-
// This will be used if there is a select_timezone set for this field
|
457 |
-
$tz_offset = $this->field->field_timezone_offset();
|
458 |
-
if ( ! empty( $tz_offset ) ) {
|
459 |
-
$meta_value -= $tz_offset;
|
460 |
-
}
|
461 |
-
$desc = $this->_desc();
|
462 |
-
}
|
463 |
-
|
464 |
-
$inputs = array(
|
465 |
-
$this->input( array(
|
466 |
-
'class' => 'cmb_text_small cmb_datepicker',
|
467 |
-
'name' => $this->_name( '[date]' ),
|
468 |
-
'id' => $this->_id( '_date' ),
|
469 |
-
'value' => ! empty( $meta_value ) ? date( $this->field->args( 'date_format' ), $meta_value ) : '',
|
470 |
-
'desc' => '',
|
471 |
-
) ),
|
472 |
-
$this->input( array(
|
473 |
-
'class' => 'cmb_timepicker text_time',
|
474 |
-
'name' => $this->_name( '[time]' ),
|
475 |
-
'id' => $this->_id( '_time' ),
|
476 |
-
'value' => ! empty( $meta_value ) ? date( $this->field->args( 'time_format' ), $meta_value ) : '',
|
477 |
-
'desc' => $desc,
|
478 |
-
) )
|
479 |
-
);
|
480 |
-
|
481 |
-
return implode( "\n", $inputs );
|
482 |
-
}
|
483 |
-
|
484 |
-
public function text_datetime_timestamp_timezone() {
|
485 |
-
$meta_value = $this->field->escaped_value();
|
486 |
-
$datetime = unserialize( $meta_value );
|
487 |
-
$meta_value = $tzstring = false;
|
488 |
-
|
489 |
-
if ( $datetime && $datetime instanceof DateTime ) {
|
490 |
-
$tz = $datetime->getTimezone();
|
491 |
-
$tzstring = $tz->getName();
|
492 |
-
$meta_value = $datetime->getTimestamp() + $tz->getOffset( new DateTime( 'NOW' ) );
|
493 |
-
}
|
494 |
-
|
495 |
-
$inputs = $this->text_datetime_timestamp( $meta_value );
|
496 |
-
$inputs .= '<select name="'. $this->_name( '[timezone]' ) .'" id="'. $this->_id( '_timezone' ) .'">';
|
497 |
-
$inputs .= wp_timezone_choice( $tzstring );
|
498 |
-
$inputs .= '</select>'. $this->_desc();
|
499 |
-
|
500 |
-
return $inputs;
|
501 |
-
}
|
502 |
-
|
503 |
-
public function select_timezone() {
|
504 |
-
$this->field->args['default'] = $this->field->args( 'default' )
|
505 |
-
? $this->field->args( 'default' )
|
506 |
-
: cmb_Meta_Box::timezone_string();
|
507 |
-
|
508 |
-
$meta_value = $this->field->escaped_value();
|
509 |
-
|
510 |
-
return '<select name="'. $this->_name() .'" id="'. $this->_id() .'">'. wp_timezone_choice( $meta_value ) .'</select>';
|
511 |
-
}
|
512 |
-
|
513 |
-
public function colorpicker() {
|
514 |
-
$meta_value = $this->field->escaped_value();
|
515 |
-
$hex_color = '(([a-fA-F0-9]){3}){1,2}$';
|
516 |
-
if ( preg_match( '/^' . $hex_color . '/i', $meta_value ) ) // Value is just 123abc, so prepend #.
|
517 |
-
$meta_value = '#' . $meta_value;
|
518 |
-
elseif ( ! preg_match( '/^#' . $hex_color . '/i', $meta_value ) ) // Value doesn't match #123abc, so sanitize to just #.
|
519 |
-
$meta_value = "#";
|
520 |
-
|
521 |
-
return $this->input( array( 'class' => 'cmb_colorpicker cmb_text_small', 'value' => $meta_value ) );
|
522 |
-
}
|
523 |
-
|
524 |
-
public function title() {
|
525 |
-
extract( $this->parse_args( array(), 'title', array(
|
526 |
-
'tag' => $this->field->object_type == 'post' ? 'h5' : 'h3',
|
527 |
-
'class' => 'cmb_metabox_title',
|
528 |
-
'name' => $this->field->args( 'name' ),
|
529 |
-
'desc' => $this->_desc( true ),
|
530 |
-
) ) );
|
531 |
-
|
532 |
-
return sprintf( '<%1$s class="%2$s">%3$s</%1$s>%4$s', $tag, $class, $name, $desc );
|
533 |
-
}
|
534 |
-
|
535 |
-
public function select( $args = array() ) {
|
536 |
-
$args = $this->parse_args( $args, 'select', array(
|
537 |
-
'class' => 'cmb_select',
|
538 |
-
'name' => $this->_name(),
|
539 |
-
'id' => $this->_id(),
|
540 |
-
'desc' => $this->_desc( true ),
|
541 |
-
'options' => $this->concat_options(),
|
542 |
-
) );
|
543 |
-
|
544 |
-
$attrs = $this->concat_attrs( $args, array( 'desc', 'options' ) );
|
545 |
-
return sprintf( '<select%s>%s</select>%s', $attrs, $args['options'], $args['desc'] );
|
546 |
-
}
|
547 |
-
|
548 |
-
public function taxonomy_select() {
|
549 |
-
|
550 |
-
$names = $this->get_object_terms();
|
551 |
-
$saved_term = is_wp_error( $names ) || empty( $names ) ? $this->field->args( 'default' ) : $names[0]->slug;
|
552 |
-
$terms = get_terms( $this->field->args( 'taxonomy' ), 'hide_empty=0' );
|
553 |
-
$options = '';
|
554 |
-
|
555 |
-
foreach ( $terms as $term ) {
|
556 |
-
$selected = $saved_term == $term->slug;
|
557 |
-
$options .= $this->option( $term->name, $term->slug, $selected );
|
558 |
-
}
|
559 |
-
|
560 |
-
return $this->select( array( 'options' => $options ) );
|
561 |
-
}
|
562 |
-
|
563 |
-
public function radio( $args = array(), $type = 'radio' ) {
|
564 |
-
extract( $this->parse_args( $args, $type, array(
|
565 |
-
'class' => 'cmb_radio_list cmb_list',
|
566 |
-
'options' => $this->concat_options( array( 'label' => 'test' ) ),
|
567 |
-
'desc' => $this->_desc( true ),
|
568 |
-
) ) );
|
569 |
-
|
570 |
-
return sprintf( '<ul class="%s">%s</ul>%s', $class, $options, $desc );
|
571 |
-
}
|
572 |
-
|
573 |
-
public function radio_inline() {
|
574 |
-
return $this->radio( array(), 'radio_inline' );
|
575 |
-
}
|
576 |
-
|
577 |
-
public function multicheck( $type = 'checkbox' ) {
|
578 |
-
return $this->radio( array( 'class' => 'cmb_checkbox_list cmb_list', 'options' => $this->concat_options( array( 'type' => 'checkbox', 'name' => $this->_name() .'[]' ), 'list_input_checkbox' ) ), $type );
|
579 |
-
}
|
580 |
-
|
581 |
-
public function multicheck_inline() {
|
582 |
-
$this->multicheck( 'multicheck_inline' );
|
583 |
-
}
|
584 |
-
|
585 |
-
public function checkbox() {
|
586 |
-
$meta_value = $this->field->escaped_value();
|
587 |
-
$args = array( 'type' => 'checkbox', 'class' => 'cmb_option cmb_list', 'value' => 'on', 'desc' => '' );
|
588 |
-
if ( ! empty( $meta_value ) ) {
|
589 |
-
$args['checked'] = 'checked';
|
590 |
-
}
|
591 |
-
return sprintf( '%s <label for="%s">%s</label>', $this->input( $args ), $this->_id(), $this->_desc() );
|
592 |
-
}
|
593 |
-
|
594 |
-
public function taxonomy_radio() {
|
595 |
-
$names = $this->get_object_terms();
|
596 |
-
$saved_term = is_wp_error( $names ) || empty( $names ) ? $this->field->args( 'default' ) : $names[0]->slug;
|
597 |
-
$terms = get_terms( $this->field->args( 'taxonomy' ), 'hide_empty=0' );
|
598 |
-
$options = ''; $i = 1;
|
599 |
-
|
600 |
-
if ( ! $terms ) {
|
601 |
-
$options .= '<li><label>'. __( 'No terms', 'cmb' ) .'</label></li>';
|
602 |
-
} else {
|
603 |
-
foreach ( $terms as $term ) {
|
604 |
-
$args = array(
|
605 |
-
'value' => $term->slug,
|
606 |
-
'label' => $term->name,
|
607 |
-
);
|
608 |
-
|
609 |
-
if ( $saved_term == $term->slug ) {
|
610 |
-
$args['checked'] = 'checked';
|
611 |
-
}
|
612 |
-
$options .= $this->list_input( $args, $i );
|
613 |
-
$i++;
|
614 |
-
}
|
615 |
-
}
|
616 |
-
|
617 |
-
return $this->radio( array( 'options' => $options ), 'taxonomy_radio' );
|
618 |
-
}
|
619 |
-
|
620 |
-
public function taxonomy_radio_inline() {
|
621 |
-
$this->taxonomy_radio();
|
622 |
-
}
|
623 |
-
|
624 |
-
public function taxonomy_multicheck() {
|
625 |
-
|
626 |
-
$names = $this->get_object_terms();
|
627 |
-
$saved_terms = is_wp_error( $names ) || empty( $names )
|
628 |
-
? $this->field->args( 'default' )
|
629 |
-
: wp_list_pluck( $names, 'slug' );
|
630 |
-
$terms = get_terms( $this->field->args( 'taxonomy' ), 'hide_empty=0' );
|
631 |
-
$name = $this->_name() .'[]';
|
632 |
-
$options = ''; $i = 1;
|
633 |
-
|
634 |
-
if ( ! $terms ) {
|
635 |
-
$options .= '<li><label>'. __( 'No terms', 'cmb' ) .'</label></li>';
|
636 |
-
} else {
|
637 |
-
|
638 |
-
foreach ( $terms as $term ) {
|
639 |
-
$args = array(
|
640 |
-
'value' => $term->slug,
|
641 |
-
'label' => $term->name,
|
642 |
-
'type' => 'checkbox',
|
643 |
-
'name' => $name,
|
644 |
-
);
|
645 |
-
|
646 |
-
if ( is_array( $saved_terms ) && in_array( $term->slug, $saved_terms ) ) {
|
647 |
-
$args['checked'] = 'checked';
|
648 |
-
}
|
649 |
-
$options .= $this->list_input( $args, $i );
|
650 |
-
$i++;
|
651 |
-
}
|
652 |
-
}
|
653 |
-
|
654 |
-
return $this->radio( array( 'class' => 'cmb_checkbox_list cmb_list', 'options' => $options ), 'taxonomy_multicheck' );
|
655 |
-
}
|
656 |
-
|
657 |
-
public function taxonomy_multicheck_inline() {
|
658 |
-
$this->taxonomy_multicheck();
|
659 |
-
}
|
660 |
-
|
661 |
-
public function file_list() {
|
662 |
-
$meta_value = $this->field->escaped_value();
|
663 |
-
|
664 |
-
$name = $this->_name();
|
665 |
-
|
666 |
-
echo $this->input( array(
|
667 |
-
'type' => 'hidden',
|
668 |
-
'class' => 'cmb_upload_file cmb_upload_list',
|
669 |
-
'size' => 45, 'desc' => '', 'value' => '',
|
670 |
-
) ),
|
671 |
-
$this->input( array(
|
672 |
-
'type' => 'button',
|
673 |
-
'class' => 'cmb_upload_button button cmb_upload_list',
|
674 |
-
'value' => __( 'Add or Upload File', 'cmb' ),
|
675 |
-
'name' => '', 'id' => '',
|
676 |
-
) );
|
677 |
-
|
678 |
-
echo '<ul id="', $this->_id( '_status' ) ,'" class="cmb_media_status attach_list">';
|
679 |
-
|
680 |
-
if ( $meta_value && is_array( $meta_value ) ) {
|
681 |
-
|
682 |
-
foreach ( $meta_value as $id => $fullurl ) {
|
683 |
-
$id_input = $this->input( array(
|
684 |
-
'type' => 'hidden',
|
685 |
-
'value' => $fullurl,
|
686 |
-
'name' => $name .'['. $id .']',
|
687 |
-
'id' => 'filelist-'. $id,
|
688 |
-
'desc' => '', 'class' => '',
|
689 |
-
) );
|
690 |
-
|
691 |
-
if ( $this->is_valid_img_ext( $fullurl ) ) {
|
692 |
-
echo
|
693 |
-
'<li class="img_status">',
|
694 |
-
wp_get_attachment_image( $id, $this->field->args( 'preview_size' ) ),
|
695 |
-
'<p class="cmb_remove_wrapper"><a href="#" class="cmb_remove_file_button">'. __( 'Remove Image', 'cmb' ) .'</a></p>
|
696 |
-
'. $id_input .'
|
697 |
-
</li>';
|
698 |
-
|
699 |
-
} else {
|
700 |
-
$parts = explode( '/', $fullurl );
|
701 |
-
for ( $i = 0; $i < count( $parts ); ++$i ) {
|
702 |
-
$title = $parts[$i];
|
703 |
-
}
|
704 |
-
echo
|
705 |
-
'<li>',
|
706 |
-
__( 'File:', 'cmb' ), ' <strong>', $title, '</strong> (<a href="', $fullurl, '" target="_blank" rel="external">'. __( 'Download', 'cmb' ) .'</a> / <a href="#" class="cmb_remove_file_button">'. __( 'Remove', 'cmb' ) .'</a>)
|
707 |
-
'. $id_input .'
|
708 |
-
</li>';
|
709 |
-
}
|
710 |
-
}
|
711 |
-
}
|
712 |
-
|
713 |
-
echo '</ul>';
|
714 |
-
}
|
715 |
-
|
716 |
-
public function file() {
|
717 |
-
$meta_value = $this->field->escaped_value();
|
718 |
-
$allow = $this->field->args( 'allow' );
|
719 |
-
$input_type = ( 'url' == $allow || ( is_array( $allow ) && in_array( 'url', $allow ) ) )
|
720 |
-
? 'text' : 'hidden';
|
721 |
-
|
722 |
-
echo $this->input( array(
|
723 |
-
'type' => $input_type,
|
724 |
-
'class' => 'cmb_upload_file',
|
725 |
-
'size' => 45,
|
726 |
-
'desc' => '',
|
727 |
-
) ),
|
728 |
-
'<input class="cmb_upload_button button" type="button" value="'. __( 'Add or Upload File', 'cmb' ) .'" />',
|
729 |
-
$this->_desc( true );
|
730 |
-
|
731 |
-
$cached_id = $this->_id();
|
732 |
-
// Reset field args for attachment ID
|
733 |
-
$args = $this->field->args();
|
734 |
-
$args['id'] = $args['_id'] . '_id';
|
735 |
-
unset( $args['_id'], $args['_name'] );
|
736 |
-
|
737 |
-
// And get new field object
|
738 |
-
$this->field = new cmb_Meta_Box_field( $args, $this->field->group );
|
739 |
-
|
740 |
-
// Get ID value
|
741 |
-
$_id_value = $this->field->escaped_value( 'absint' );
|
742 |
-
|
743 |
-
// If there is no ID saved yet, try to get it from the url
|
744 |
-
if ( $meta_value && ! $_id_value ) {
|
745 |
-
$_id_value = cmb_Meta_Box::image_id_from_url( esc_url_raw( $meta_value ) );
|
746 |
-
}
|
747 |
-
|
748 |
-
echo $this->input( array(
|
749 |
-
'type' => 'hidden',
|
750 |
-
'class' => 'cmb_upload_file_id',
|
751 |
-
'value' => $_id_value,
|
752 |
-
'desc' => '',
|
753 |
-
) ),
|
754 |
-
'<div id="', $this->_id( '_status' ) ,'" class="cmb_media_status">';
|
755 |
-
if ( ! empty( $meta_value ) ) {
|
756 |
-
|
757 |
-
if ( $this->is_valid_img_ext( $meta_value ) ) {
|
758 |
-
echo '<div class="img_status">';
|
759 |
-
echo '<img style="max-width: 350px; width: 100%; height: auto;" src="', $meta_value, '" alt="" />';
|
760 |
-
echo '<p class="cmb_remove_wrapper"><a href="#" class="cmb_remove_file_button" rel="', $cached_id, '">'. __( 'Remove Image', 'cmb' ) .'</a></p>';
|
761 |
-
echo '</div>';
|
762 |
-
} else {
|
763 |
-
// $file_ext = $this->get_file_ext( $meta_value );
|
764 |
-
$parts = explode( '/', $meta_value );
|
765 |
-
for ( $i = 0; $i < count( $parts ); ++$i ) {
|
766 |
-
$title = $parts[$i];
|
767 |
-
}
|
768 |
-
echo __( 'File:', 'cmb' ), ' <strong>', $title, '</strong> (<a href="', $meta_value, '" target="_blank" rel="external">'. __( 'Download', 'cmb' ) .'</a> / <a href="#" class="cmb_remove_file_button" rel="', $cached_id, '">'. __( 'Remove', 'cmb' ) .'</a>)';
|
769 |
-
}
|
770 |
-
}
|
771 |
-
echo '</div>';
|
772 |
-
}
|
773 |
-
|
774 |
-
public function oembed() {
|
775 |
-
echo $this->input( array(
|
776 |
-
'class' => 'cmb_oembed regular-text',
|
777 |
-
'data-objectid' => $this->field->object_id,
|
778 |
-
'data-objecttype' => $this->field->object_type
|
779 |
-
) ),
|
780 |
-
'<p class="cmb-spinner spinner" style="display:none;"><img src="'. admin_url( '/images/wpspin_light.gif' ) .'" alt="spinner"/></p>',
|
781 |
-
'<div id="',$this->_id( '_status' ) ,'" class="cmb_media_status ui-helper-clearfix embed_wrap">';
|
782 |
-
|
783 |
-
if ( $meta_value = $this->field->escaped_value() ) {
|
784 |
-
echo cmb_Meta_Box_ajax::get_oembed( $meta_value, $this->field->object_id, array(
|
785 |
-
'object_type' => $this->field->object_type,
|
786 |
-
'oembed_args' => array( 'width' => '640' ),
|
787 |
-
'field_id' => $this->_id(),
|
788 |
-
) );
|
789 |
-
}
|
790 |
-
|
791 |
-
echo '</div>';
|
792 |
-
}
|
793 |
-
|
794 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* CMB field types
|
5 |
+
*
|
6 |
+
* @todo test taxonomy methods with non-post objects
|
7 |
+
* @todo test all methods with non-post objects
|
8 |
+
* @todo Date/Time fields should store date format as data attribute for JS
|
9 |
+
*
|
10 |
+
* @since 1.0.0
|
11 |
+
*/
|
12 |
+
class cmb_Meta_Box_types {
|
13 |
+
|
14 |
+
/**
|
15 |
+
* An iterator value for repeatable fields
|
16 |
+
* @var integer
|
17 |
+
* @since 1.0.0
|
18 |
+
*/
|
19 |
+
public $iterator = 0;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Current field
|
23 |
+
* @var array
|
24 |
+
* @since 1.0.0
|
25 |
+
*/
|
26 |
+
public $field;
|
27 |
+
|
28 |
+
public function __construct( $field ) {
|
29 |
+
$this->field = $field;
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Default fallback. Allows rendering fields via "cmb_render_$name" hook
|
34 |
+
* @since 1.0.0
|
35 |
+
* @param string $name Non-existent method name
|
36 |
+
* @param array $arguments All arguments passed to the method
|
37 |
+
*/
|
38 |
+
public function __call( $name, $arguments ) {
|
39 |
+
// When a non-registered field is called, send it through an action.
|
40 |
+
do_action( "cmb_render_$name", $this->field->args(), $this->field->escaped_value(), $this->field->object_id, $this->field->object_type, $this );
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Render a field (and handle repeatable)
|
45 |
+
* @since 1.1.0
|
46 |
+
*/
|
47 |
+
public function render() {
|
48 |
+
if ( $this->field->args( 'repeatable' ) ) {
|
49 |
+
$this->render_repeatable_field();
|
50 |
+
} else {
|
51 |
+
$this->_render();
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Render a field type
|
57 |
+
* @since 1.1.0
|
58 |
+
*/
|
59 |
+
protected function _render() {
|
60 |
+
echo $this->{$this->field->type()}();
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Checks if we can get a post object, and if so, uses `get_the_terms` which utilizes caching
|
65 |
+
* @since 1.0.2
|
66 |
+
* @return mixed Array of terms on success
|
67 |
+
*/
|
68 |
+
public function get_object_terms() {
|
69 |
+
$object_id = $this->field->object_id;
|
70 |
+
$taxonomy = $this->field->args( 'taxonomy' );
|
71 |
+
|
72 |
+
if ( ! $post = get_post( $object_id ) ) {
|
73 |
+
|
74 |
+
$cache_key = 'cmb-cache-'. $taxonomy .'-'. $object_id;
|
75 |
+
|
76 |
+
// Check cache
|
77 |
+
$cached = $test = get_transient( $cache_key );
|
78 |
+
if ( $cached )
|
79 |
+
return $cached;
|
80 |
+
|
81 |
+
$cached = wp_get_object_terms( $object_id, $taxonomy );
|
82 |
+
// Do our own (minimal) caching. Long enough for a page-load.
|
83 |
+
$set = set_transient( $cache_key, $cached, 60 );
|
84 |
+
return $cached;
|
85 |
+
}
|
86 |
+
|
87 |
+
// WP caches internally so it's better to use
|
88 |
+
return get_the_terms( $post, $taxonomy );
|
89 |
+
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Determine a file's extension
|
94 |
+
* @since 1.0.0
|
95 |
+
* @param string $file File url
|
96 |
+
* @return string|false File extension or false
|
97 |
+
*/
|
98 |
+
public function get_file_ext( $file ) {
|
99 |
+
$parsed = @parse_url( $file, PHP_URL_PATH );
|
100 |
+
return $parsed ? strtolower( pathinfo( $parsed, PATHINFO_EXTENSION ) ) : false;
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Determines if a file has a valid image extension
|
105 |
+
* @since 1.0.0
|
106 |
+
* @param string $file File url
|
107 |
+
* @return bool Whether file has a valid image extension
|
108 |
+
*/
|
109 |
+
public function is_valid_img_ext( $file ) {
|
110 |
+
$file_ext = $this->get_file_ext( $file );
|
111 |
+
|
112 |
+
$this->valid = empty( $this->valid )
|
113 |
+
? (array) apply_filters( 'cmb_valid_img_types', array( 'jpg', 'jpeg', 'png', 'gif', 'ico', 'icon' ) )
|
114 |
+
: $this->valid;
|
115 |
+
|
116 |
+
return ( $file_ext && in_array( $file_ext, $this->valid ) );
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Handles parsing and filtering attributes while preserving any passed in via field config.
|
121 |
+
* @since 1.1.0
|
122 |
+
* @param array $args Override arguments
|
123 |
+
* @param string $element Element for filter
|
124 |
+
* @param array $defaults Default arguments
|
125 |
+
* @return array Parsed and filtered arguments
|
126 |
+
*/
|
127 |
+
public function parse_args( $args, $element, $defaults ) {
|
128 |
+
return wp_parse_args( apply_filters( "cmb_{$element}_attributes", $this->field->maybe_set_attributes( $args ), $this->field, $this ), $defaults );
|
129 |
+
}
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Combines attributes into a string for a form element
|
133 |
+
* @since 1.1.0
|
134 |
+
* @param array $attrs Attributes to concatenate
|
135 |
+
* @param array $attr_exclude Attributes that should NOT be concatenated
|
136 |
+
* @return string String of attributes for form element
|
137 |
+
*/
|
138 |
+
public function concat_attrs( $attrs, $attr_exclude = array() ) {
|
139 |
+
$attributes = '';
|
140 |
+
foreach ( $attrs as $attr => $val ) {
|
141 |
+
if ( ! in_array( $attr, (array) $attr_exclude, true ) )
|
142 |
+
$attributes .= sprintf( ' %s="%s"', $attr, $val );
|
143 |
+
}
|
144 |
+
return $attributes;
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Generates html for an option element
|
149 |
+
* @since 1.1.0
|
150 |
+
* @param string $opt_label Option label
|
151 |
+
* @param string $opt_value Option value
|
152 |
+
* @param mixed $selected Selected attribute if option is selected
|
153 |
+
* @return string Generated option element html
|
154 |
+
*/
|
155 |
+
public function option( $opt_label, $opt_value, $selected ) {
|
156 |
+
return sprintf( "\t".'<option value="%s" %s>%s</option>', $opt_value, selected( $selected, true, false ), $opt_label )."\n";
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* Generates options html
|
161 |
+
* @since 1.1.0
|
162 |
+
* @param array $args Optional arguments
|
163 |
+
* @param string $method Method to generate individual option item
|
164 |
+
* @return string Concatenated html options
|
165 |
+
*/
|
166 |
+
public function concat_options( $args = array(), $method = 'list_input' ) {
|
167 |
+
|
168 |
+
$options = (array) $this->field->args( 'options' );
|
169 |
+
$saved_value = $this->field->escaped_value();
|
170 |
+
$value = $saved_value ? $saved_value : $this->field->args( 'default' );
|
171 |
+
|
172 |
+
$_options = ''; $i = 1;
|
173 |
+
foreach ( $options as $option_key => $option ) {
|
174 |
+
|
175 |
+
// Check for the "old" way
|
176 |
+
$opt_label = is_array( $option ) && array_key_exists( 'name', $option ) ? $option['name'] : $option;
|
177 |
+
$opt_value = is_array( $option ) && array_key_exists( 'value', $option ) ? $option['value'] : $option_key;
|
178 |
+
// Check if this option is the value of the input
|
179 |
+
$is_current = $value == $opt_value;
|
180 |
+
|
181 |
+
if ( ! empty( $args ) ) {
|
182 |
+
// Clone args & modify for just this item
|
183 |
+
$this_args = $args;
|
184 |
+
$this_args['value'] = $opt_value;
|
185 |
+
$this_args['label'] = $opt_label;
|
186 |
+
if ( $is_current )
|
187 |
+
$this_args['checked'] = 'checked';
|
188 |
+
|
189 |
+
$_options .= $this->$method( $this_args, $i );
|
190 |
+
} else {
|
191 |
+
$_options .= $this->option( $opt_label, $opt_value, $is_current );
|
192 |
+
}
|
193 |
+
$i++;
|
194 |
+
}
|
195 |
+
return $_options;
|
196 |
+
}
|
197 |
+
|
198 |
+
/**
|
199 |
+
* Generates html for list item with input
|
200 |
+
* @since 1.1.0
|
201 |
+
* @param array $args Override arguments
|
202 |
+
* @param int $i Iterator value
|
203 |
+
* @return string Gnerated list item html
|
204 |
+
*/
|
205 |
+
public function list_input( $args = array(), $i ) {
|
206 |
+
$args = $this->parse_args( $args, 'list_input', array(
|
207 |
+
'type' => 'radio',
|
208 |
+
'class' => 'cmb_option',
|
209 |
+
'name' => $this->_name(),
|
210 |
+
'id' => $this->_id( $i ),
|
211 |
+
'value' => $this->field->escaped_value(),
|
212 |
+
'label' => '',
|
213 |
+
) );
|
214 |
+
|
215 |
+
return sprintf( "\t".'<li><input%s/> <label for="%s">%s</label></li>'."\n", $this->concat_attrs( $args, 'label' ), $args['id'], $args['label'] );
|
216 |
+
}
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Generates html for list item with checkbox input
|
220 |
+
* @since 1.1.0
|
221 |
+
* @param array $args Override arguments
|
222 |
+
* @param int $i Iterator value
|
223 |
+
* @return string Gnerated list item html
|
224 |
+
*/
|
225 |
+
public function list_input_checkbox( $args, $i ) {
|
226 |
+
unset( $args['selected'] );
|
227 |
+
$saved_value = $this->field->escaped_value();
|
228 |
+
if ( is_array( $saved_value ) && in_array( $args['value'], $saved_value ) ) {
|
229 |
+
$args['checked'] = 'checked';
|
230 |
+
}
|
231 |
+
return $this->list_input( $args, $i );
|
232 |
+
}
|
233 |
+
|
234 |
+
/**
|
235 |
+
* Generates repeatable field table markup
|
236 |
+
* @since 1.0.0
|
237 |
+
*/
|
238 |
+
public function render_repeatable_field() {
|
239 |
+
$table_id = $this->field->id() .'_repeat';
|
240 |
+
|
241 |
+
$this->_desc( true, true );
|
242 |
+
?>
|
243 |
+
|
244 |
+
<table id="<?php echo $table_id; ?>" class="cmb-repeat-table">
|
245 |
+
<tbody>
|
246 |
+
<?php $this->repeatable_rows(); ?>
|
247 |
+
</tbody>
|
248 |
+
</table>
|
249 |
+
<p class="add-row">
|
250 |
+
<a data-selector="<?php echo $table_id; ?>" class="add-row-button button" href="#"><?php _e( 'Add Row', 'cmb' ); ?></a>
|
251 |
+
</p>
|
252 |
+
|
253 |
+
<?php
|
254 |
+
// reset iterator
|
255 |
+
$this->iterator = 0;
|
256 |
+
}
|
257 |
+
|
258 |
+
/**
|
259 |
+
* Generates repeatable field rows
|
260 |
+
* @since 1.1.0
|
261 |
+
*/
|
262 |
+
public function repeatable_rows() {
|
263 |
+
$meta_value = $this->field->escaped_value();
|
264 |
+
// check for default content
|
265 |
+
$default = $this->field->args( 'default' );
|
266 |
+
|
267 |
+
// check for saved data
|
268 |
+
if ( ! empty( $meta_value ) ) {
|
269 |
+
$meta_value = is_array( $meta_value ) ? array_filter( $meta_value ) : $meta_value;
|
270 |
+
$meta_value = ! empty( $meta_value ) ? $meta_value : $default;
|
271 |
+
} else {
|
272 |
+
$meta_value = $default;
|
273 |
+
}
|
274 |
+
|
275 |
+
// Loop value array and add a row
|
276 |
+
if ( ! empty( $meta_value ) ) {
|
277 |
+
foreach ( (array) $meta_value as $val ) {
|
278 |
+
$this->field->escaped_value = $val;
|
279 |
+
$this->repeat_row();
|
280 |
+
$this->iterator++;
|
281 |
+
}
|
282 |
+
} else {
|
283 |
+
// Otherwise add one row
|
284 |
+
$this->repeat_row();
|
285 |
+
}
|
286 |
+
|
287 |
+
// Then add an empty row
|
288 |
+
$this->field->escaped_value = '';
|
289 |
+
$this->iterator = $this->iterator ? $this->iterator : 1;
|
290 |
+
$this->repeat_row( 'empty-row' );
|
291 |
+
}
|
292 |
+
|
293 |
+
/**
|
294 |
+
* Generates a repeatable row's markup
|
295 |
+
* @since 1.1.0
|
296 |
+
* @param string $class Repeatable table row's class
|
297 |
+
*/
|
298 |
+
protected function repeat_row( $class = 'repeat-row' ) {
|
299 |
+
?>
|
300 |
+
|
301 |
+
<tr class="<?php echo $class; ?>">
|
302 |
+
<td>
|
303 |
+
<?php $this->_render(); ?>
|
304 |
+
</td>
|
305 |
+
<td class="remove-row">
|
306 |
+
<a class="button remove-row-button" href="#"><?php _e( 'Remove', 'cmb' ); ?></a>
|
307 |
+
</td>
|
308 |
+
</tr>
|
309 |
+
|
310 |
+
<?php
|
311 |
+
}
|
312 |
+
|
313 |
+
/**
|
314 |
+
* Generates description markup
|
315 |
+
* @since 1.0.0
|
316 |
+
* @param boolean $paragraph Paragraph tag or span
|
317 |
+
* @param boolean $echo Whether to echo description or only return it
|
318 |
+
* @return string Field's description markup
|
319 |
+
*/
|
320 |
+
public function _desc( $paragraph = false, $echo = false ) {
|
321 |
+
// Prevent description from printing multiple times for repeatable fields
|
322 |
+
if ( $this->field->args( 'repeatable' ) || $this->iterator > 0 ) {
|
323 |
+
return '';
|
324 |
+
}
|
325 |
+
$tag = $paragraph ? 'p' : 'span';
|
326 |
+
$desc = "\n<$tag class=\"cmb_metabox_description\">{$this->field->args( 'description' )}</$tag>\n";
|
327 |
+
if ( $echo )
|
328 |
+
echo $desc;
|
329 |
+
return $desc;
|
330 |
+
}
|
331 |
+
|
332 |
+
/**
|
333 |
+
* Generate field name attribute
|
334 |
+
* @since 1.1.0
|
335 |
+
* @param string $suffix For multi-part fields
|
336 |
+
* @return string Name attribute
|
337 |
+
*/
|
338 |
+
public function _name( $suffix = '' ) {
|
339 |
+
return $this->field->args( '_name' ) . ( $this->field->args( 'repeatable' ) ? '['. $this->iterator .']' : '' ) . $suffix;
|
340 |
+
}
|
341 |
+
|
342 |
+
/**
|
343 |
+
* Generate field id attribute
|
344 |
+
* @since 1.1.0
|
345 |
+
* @param string $suffix For multi-part fields
|
346 |
+
* @return string Id attribute
|
347 |
+
*/
|
348 |
+
public function _id( $suffix = '' ) {
|
349 |
+
return $this->field->id() . $suffix . ( $this->field->args( 'repeatable' ) ? '_'. $this->iterator .'" data-iterator="'. $this->iterator : '' );
|
350 |
+
}
|
351 |
+
|
352 |
+
/**
|
353 |
+
* Handles outputting an 'input' element
|
354 |
+
* @since 1.1.0
|
355 |
+
* @param array $args Override arguments
|
356 |
+
* @return string Form input element
|
357 |
+
*/
|
358 |
+
public function input( $args = array() ) {
|
359 |
+
$args = $this->parse_args( $args, 'input', array(
|
360 |
+
'type' => 'text',
|
361 |
+
'class' => 'regular-text',
|
362 |
+
'name' => $this->_name(),
|
363 |
+
'id' => $this->_id(),
|
364 |
+
'value' => $this->field->escaped_value(),
|
365 |
+
'desc' => $this->_desc( true ),
|
366 |
+
) );
|
367 |
+
|
368 |
+
return sprintf( '<input%s/>%s', $this->concat_attrs( $args, 'desc' ), $args['desc'] );
|
369 |
+
}
|
370 |
+
|
371 |
+
/**
|
372 |
+
* Handles outputting an 'textarea' element
|
373 |
+
* @since 1.1.0
|
374 |
+
* @param array $args Override arguments
|
375 |
+
* @return string Form textarea element
|
376 |
+
*/
|
377 |
+
public function textarea( $args = array() ) {
|
378 |
+
$args = $this->parse_args( $args, 'textarea', array(
|
379 |
+
'class' => 'cmb_textarea',
|
380 |
+
'name' => $this->_name(),
|
381 |
+
'id' => $this->_id(),
|
382 |
+
'cols' => 60,
|
383 |
+
'rows' => 10,
|
384 |
+
'value' => $this->field->escaped_value( 'esc_textarea' ),
|
385 |
+
'desc' => $this->_desc( true ),
|
386 |
+
) );
|
387 |
+
return sprintf( '<textarea%s>%s</textarea>%s', $this->concat_attrs( $args, array( 'desc', 'value' ) ), $args['value'], $args['desc'] );
|
388 |
+
}
|
389 |
+
|
390 |
+
/**
|
391 |
+
* Begin Field Types
|
392 |
+
*/
|
393 |
+
|
394 |
+
public function text() {
|
395 |
+
return $this->input();
|
396 |
+
}
|
397 |
+
|
398 |
+
public function text_small() {
|
399 |
+
return $this->input( array( 'class' => 'cmb_text_small', 'desc' => $this->_desc() ) );
|
400 |
+
}
|
401 |
+
|
402 |
+
public function text_medium() {
|
403 |
+
return $this->input( array( 'class' => 'cmb_text_medium', 'desc' => $this->_desc() ) );
|
404 |
+
}
|
405 |
+
|
406 |
+
public function text_email() {
|
407 |
+
return $this->input( array( 'class' => 'cmb_text_email cmb_text_medium', 'type' => 'email' ) );
|
408 |
+
}
|
409 |
+
|
410 |
+
public function text_url() {
|
411 |
+
return $this->input( array( 'class' => 'cmb_text_url cmb_text_medium regular-text', 'value' => $this->field->escaped_value( 'esc_url' ) ) );
|
412 |
+
}
|
413 |
+
|
414 |
+
public function text_date() {
|
415 |
+
return $this->input( array( 'class' => 'cmb_text_small cmb_datepicker', 'desc' => $this->_desc() ) );
|
416 |
+
}
|
417 |
+
|
418 |
+
public function text_time() {
|
419 |
+
return $this->input( array( 'class' => 'cmb_timepicker text_time', 'desc' => $this->_desc() ) );
|
420 |
+
}
|
421 |
+
|
422 |
+
public function text_money() {
|
423 |
+
return ( ! $this->field->args( 'before' ) ? '$ ' : ' ' ) . $this->input( array( 'class' => 'cmb_text_money', 'desc' => $this->_desc() ) );
|
424 |
+
}
|
425 |
+
|
426 |
+
public function textarea_small() {
|
427 |
+
return $this->textarea( array( 'class' => 'cmb_textarea_small', 'rows' => 4 ) );
|
428 |
+
}
|
429 |
+
|
430 |
+
public function textarea_code() {
|
431 |
+
return sprintf( '<pre>%s</pre>', $this->textarea( array( 'class' => 'cmb_textarea_code' ) ) );
|
432 |
+
}
|
433 |
+
|
434 |
+
public function wysiwyg( $args = array() ) {
|
435 |
+
extract( $this->parse_args( $args, 'input', array(
|
436 |
+
'id' => $this->_id(),
|
437 |
+
'value' => $this->field->escaped_value( 'stripslashes' ),
|
438 |
+
'desc' => $this->_desc( true ),
|
439 |
+
'options' => $this->field->args( 'options' ),
|
440 |
+
) ) );
|
441 |
+
|
442 |
+
wp_editor( $value, $id, $options );
|
443 |
+
echo $desc;
|
444 |
+
}
|
445 |
+
|
446 |
+
public function text_date_timestamp() {
|
447 |
+
$meta_value = $this->field->escaped_value();
|
448 |
+
$value = ! empty( $meta_value ) ? date( $this->field->args( 'date_format' ), $meta_value ) : '';
|
449 |
+
return $this->input( array( 'class' => 'cmb_text_small cmb_datepicker', 'value' => $value ) );
|
450 |
+
}
|
451 |
+
|
452 |
+
public function text_datetime_timestamp( $meta_value = '' ) {
|
453 |
+
$desc = '';
|
454 |
+
if ( ! $meta_value ) {
|
455 |
+
$meta_value = $this->field->escaped_value();
|
456 |
+
// This will be used if there is a select_timezone set for this field
|
457 |
+
$tz_offset = $this->field->field_timezone_offset();
|
458 |
+
if ( ! empty( $tz_offset ) ) {
|
459 |
+
$meta_value -= $tz_offset;
|
460 |
+
}
|
461 |
+
$desc = $this->_desc();
|
462 |
+
}
|
463 |
+
|
464 |
+
$inputs = array(
|
465 |
+
$this->input( array(
|
466 |
+
'class' => 'cmb_text_small cmb_datepicker',
|
467 |
+
'name' => $this->_name( '[date]' ),
|
468 |
+
'id' => $this->_id( '_date' ),
|
469 |
+
'value' => ! empty( $meta_value ) ? date( $this->field->args( 'date_format' ), $meta_value ) : '',
|
470 |
+
'desc' => '',
|
471 |
+
) ),
|
472 |
+
$this->input( array(
|
473 |
+
'class' => 'cmb_timepicker text_time',
|
474 |
+
'name' => $this->_name( '[time]' ),
|
475 |
+
'id' => $this->_id( '_time' ),
|
476 |
+
'value' => ! empty( $meta_value ) ? date( $this->field->args( 'time_format' ), $meta_value ) : '',
|
477 |
+
'desc' => $desc,
|
478 |
+
) )
|
479 |
+
);
|
480 |
+
|
481 |
+
return implode( "\n", $inputs );
|
482 |
+
}
|
483 |
+
|
484 |
+
public function text_datetime_timestamp_timezone() {
|
485 |
+
$meta_value = $this->field->escaped_value();
|
486 |
+
$datetime = unserialize( $meta_value );
|
487 |
+
$meta_value = $tzstring = false;
|
488 |
+
|
489 |
+
if ( $datetime && $datetime instanceof DateTime ) {
|
490 |
+
$tz = $datetime->getTimezone();
|
491 |
+
$tzstring = $tz->getName();
|
492 |
+
$meta_value = $datetime->getTimestamp() + $tz->getOffset( new DateTime( 'NOW' ) );
|
493 |
+
}
|
494 |
+
|
495 |
+
$inputs = $this->text_datetime_timestamp( $meta_value );
|
496 |
+
$inputs .= '<select name="'. $this->_name( '[timezone]' ) .'" id="'. $this->_id( '_timezone' ) .'">';
|
497 |
+
$inputs .= wp_timezone_choice( $tzstring );
|
498 |
+
$inputs .= '</select>'. $this->_desc();
|
499 |
+
|
500 |
+
return $inputs;
|
501 |
+
}
|
502 |
+
|
503 |
+
public function select_timezone() {
|
504 |
+
$this->field->args['default'] = $this->field->args( 'default' )
|
505 |
+
? $this->field->args( 'default' )
|
506 |
+
: cmb_Meta_Box::timezone_string();
|
507 |
+
|
508 |
+
$meta_value = $this->field->escaped_value();
|
509 |
+
|
510 |
+
return '<select name="'. $this->_name() .'" id="'. $this->_id() .'">'. wp_timezone_choice( $meta_value ) .'</select>';
|
511 |
+
}
|
512 |
+
|
513 |
+
public function colorpicker() {
|
514 |
+
$meta_value = $this->field->escaped_value();
|
515 |
+
$hex_color = '(([a-fA-F0-9]){3}){1,2}$';
|
516 |
+
if ( preg_match( '/^' . $hex_color . '/i', $meta_value ) ) // Value is just 123abc, so prepend #.
|
517 |
+
$meta_value = '#' . $meta_value;
|
518 |
+
elseif ( ! preg_match( '/^#' . $hex_color . '/i', $meta_value ) ) // Value doesn't match #123abc, so sanitize to just #.
|
519 |
+
$meta_value = "#";
|
520 |
+
|
521 |
+
return $this->input( array( 'class' => 'cmb_colorpicker cmb_text_small', 'value' => $meta_value ) );
|
522 |
+
}
|
523 |
+
|
524 |
+
public function title() {
|
525 |
+
extract( $this->parse_args( array(), 'title', array(
|
526 |
+
'tag' => $this->field->object_type == 'post' ? 'h5' : 'h3',
|
527 |
+
'class' => 'cmb_metabox_title',
|
528 |
+
'name' => $this->field->args( 'name' ),
|
529 |
+
'desc' => $this->_desc( true ),
|
530 |
+
) ) );
|
531 |
+
|
532 |
+
return sprintf( '<%1$s class="%2$s">%3$s</%1$s>%4$s', $tag, $class, $name, $desc );
|
533 |
+
}
|
534 |
+
|
535 |
+
public function select( $args = array() ) {
|
536 |
+
$args = $this->parse_args( $args, 'select', array(
|
537 |
+
'class' => 'cmb_select',
|
538 |
+
'name' => $this->_name(),
|
539 |
+
'id' => $this->_id(),
|
540 |
+
'desc' => $this->_desc( true ),
|
541 |
+
'options' => $this->concat_options(),
|
542 |
+
) );
|
543 |
+
|
544 |
+
$attrs = $this->concat_attrs( $args, array( 'desc', 'options' ) );
|
545 |
+
return sprintf( '<select%s>%s</select>%s', $attrs, $args['options'], $args['desc'] );
|
546 |
+
}
|
547 |
+
|
548 |
+
public function taxonomy_select() {
|
549 |
+
|
550 |
+
$names = $this->get_object_terms();
|
551 |
+
$saved_term = is_wp_error( $names ) || empty( $names ) ? $this->field->args( 'default' ) : $names[0]->slug;
|
552 |
+
$terms = get_terms( $this->field->args( 'taxonomy' ), 'hide_empty=0' );
|
553 |
+
$options = '';
|
554 |
+
|
555 |
+
foreach ( $terms as $term ) {
|
556 |
+
$selected = $saved_term == $term->slug;
|
557 |
+
$options .= $this->option( $term->name, $term->slug, $selected );
|
558 |
+
}
|
559 |
+
|
560 |
+
return $this->select( array( 'options' => $options ) );
|
561 |
+
}
|
562 |
+
|
563 |
+
public function radio( $args = array(), $type = 'radio' ) {
|
564 |
+
extract( $this->parse_args( $args, $type, array(
|
565 |
+
'class' => 'cmb_radio_list cmb_list',
|
566 |
+
'options' => $this->concat_options( array( 'label' => 'test' ) ),
|
567 |
+
'desc' => $this->_desc( true ),
|
568 |
+
) ) );
|
569 |
+
|
570 |
+
return sprintf( '<ul class="%s">%s</ul>%s', $class, $options, $desc );
|
571 |
+
}
|
572 |
+
|
573 |
+
public function radio_inline() {
|
574 |
+
return $this->radio( array(), 'radio_inline' );
|
575 |
+
}
|
576 |
+
|
577 |
+
public function multicheck( $type = 'checkbox' ) {
|
578 |
+
return $this->radio( array( 'class' => 'cmb_checkbox_list cmb_list', 'options' => $this->concat_options( array( 'type' => 'checkbox', 'name' => $this->_name() .'[]' ), 'list_input_checkbox' ) ), $type );
|
579 |
+
}
|
580 |
+
|
581 |
+
public function multicheck_inline() {
|
582 |
+
$this->multicheck( 'multicheck_inline' );
|
583 |
+
}
|
584 |
+
|
585 |
+
public function checkbox() {
|
586 |
+
$meta_value = $this->field->escaped_value();
|
587 |
+
$args = array( 'type' => 'checkbox', 'class' => 'cmb_option cmb_list', 'value' => 'on', 'desc' => '' );
|
588 |
+
if ( ! empty( $meta_value ) ) {
|
589 |
+
$args['checked'] = 'checked';
|
590 |
+
}
|
591 |
+
return sprintf( '%s <label for="%s">%s</label>', $this->input( $args ), $this->_id(), $this->_desc() );
|
592 |
+
}
|
593 |
+
|
594 |
+
public function taxonomy_radio() {
|
595 |
+
$names = $this->get_object_terms();
|
596 |
+
$saved_term = is_wp_error( $names ) || empty( $names ) ? $this->field->args( 'default' ) : $names[0]->slug;
|
597 |
+
$terms = get_terms( $this->field->args( 'taxonomy' ), 'hide_empty=0' );
|
598 |
+
$options = ''; $i = 1;
|
599 |
+
|
600 |
+
if ( ! $terms ) {
|
601 |
+
$options .= '<li><label>'. __( 'No terms', 'cmb' ) .'</label></li>';
|
602 |
+
} else {
|
603 |
+
foreach ( $terms as $term ) {
|
604 |
+
$args = array(
|
605 |
+
'value' => $term->slug,
|
606 |
+
'label' => $term->name,
|
607 |
+
);
|
608 |
+
|
609 |
+
if ( $saved_term == $term->slug ) {
|
610 |
+
$args['checked'] = 'checked';
|
611 |
+
}
|
612 |
+
$options .= $this->list_input( $args, $i );
|
613 |
+
$i++;
|
614 |
+
}
|
615 |
+
}
|
616 |
+
|
617 |
+
return $this->radio( array( 'options' => $options ), 'taxonomy_radio' );
|
618 |
+
}
|
619 |
+
|
620 |
+
public function taxonomy_radio_inline() {
|
621 |
+
$this->taxonomy_radio();
|
622 |
+
}
|
623 |
+
|
624 |
+
public function taxonomy_multicheck() {
|
625 |
+
|
626 |
+
$names = $this->get_object_terms();
|
627 |
+
$saved_terms = is_wp_error( $names ) || empty( $names )
|
628 |
+
? $this->field->args( 'default' )
|
629 |
+
: wp_list_pluck( $names, 'slug' );
|
630 |
+
$terms = get_terms( $this->field->args( 'taxonomy' ), 'hide_empty=0' );
|
631 |
+
$name = $this->_name() .'[]';
|
632 |
+
$options = ''; $i = 1;
|
633 |
+
|
634 |
+
if ( ! $terms ) {
|
635 |
+
$options .= '<li><label>'. __( 'No terms', 'cmb' ) .'</label></li>';
|
636 |
+
} else {
|
637 |
+
|
638 |
+
foreach ( $terms as $term ) {
|
639 |
+
$args = array(
|
640 |
+
'value' => $term->slug,
|
641 |
+
'label' => $term->name,
|
642 |
+
'type' => 'checkbox',
|
643 |
+
'name' => $name,
|
644 |
+
);
|
645 |
+
|
646 |
+
if ( is_array( $saved_terms ) && in_array( $term->slug, $saved_terms ) ) {
|
647 |
+
$args['checked'] = 'checked';
|
648 |
+
}
|
649 |
+
$options .= $this->list_input( $args, $i );
|
650 |
+
$i++;
|
651 |
+
}
|
652 |
+
}
|
653 |
+
|
654 |
+
return $this->radio( array( 'class' => 'cmb_checkbox_list cmb_list', 'options' => $options ), 'taxonomy_multicheck' );
|
655 |
+
}
|
656 |
+
|
657 |
+
public function taxonomy_multicheck_inline() {
|
658 |
+
$this->taxonomy_multicheck();
|
659 |
+
}
|
660 |
+
|
661 |
+
public function file_list() {
|
662 |
+
$meta_value = $this->field->escaped_value();
|
663 |
+
|
664 |
+
$name = $this->_name();
|
665 |
+
|
666 |
+
echo $this->input( array(
|
667 |
+
'type' => 'hidden',
|
668 |
+
'class' => 'cmb_upload_file cmb_upload_list',
|
669 |
+
'size' => 45, 'desc' => '', 'value' => '',
|
670 |
+
) ),
|
671 |
+
$this->input( array(
|
672 |
+
'type' => 'button',
|
673 |
+
'class' => 'cmb_upload_button button cmb_upload_list',
|
674 |
+
'value' => __( 'Add or Upload File', 'cmb' ),
|
675 |
+
'name' => '', 'id' => '',
|
676 |
+
) );
|
677 |
+
|
678 |
+
echo '<ul id="', $this->_id( '_status' ) ,'" class="cmb_media_status attach_list">';
|
679 |
+
|
680 |
+
if ( $meta_value && is_array( $meta_value ) ) {
|
681 |
+
|
682 |
+
foreach ( $meta_value as $id => $fullurl ) {
|
683 |
+
$id_input = $this->input( array(
|
684 |
+
'type' => 'hidden',
|
685 |
+
'value' => $fullurl,
|
686 |
+
'name' => $name .'['. $id .']',
|
687 |
+
'id' => 'filelist-'. $id,
|
688 |
+
'desc' => '', 'class' => '',
|
689 |
+
) );
|
690 |
+
|
691 |
+
if ( $this->is_valid_img_ext( $fullurl ) ) {
|
692 |
+
echo
|
693 |
+
'<li class="img_status">',
|
694 |
+
wp_get_attachment_image( $id, $this->field->args( 'preview_size' ) ),
|
695 |
+
'<p class="cmb_remove_wrapper"><a href="#" class="cmb_remove_file_button">'. __( 'Remove Image', 'cmb' ) .'</a></p>
|
696 |
+
'. $id_input .'
|
697 |
+
</li>';
|
698 |
+
|
699 |
+
} else {
|
700 |
+
$parts = explode( '/', $fullurl );
|
701 |
+
for ( $i = 0; $i < count( $parts ); ++$i ) {
|
702 |
+
$title = $parts[$i];
|
703 |
+
}
|
704 |
+
echo
|
705 |
+
'<li>',
|
706 |
+
__( 'File:', 'cmb' ), ' <strong>', $title, '</strong> (<a href="', $fullurl, '" target="_blank" rel="external">'. __( 'Download', 'cmb' ) .'</a> / <a href="#" class="cmb_remove_file_button">'. __( 'Remove', 'cmb' ) .'</a>)
|
707 |
+
'. $id_input .'
|
708 |
+
</li>';
|
709 |
+
}
|
710 |
+
}
|
711 |
+
}
|
712 |
+
|
713 |
+
echo '</ul>';
|
714 |
+
}
|
715 |
+
|
716 |
+
public function file() {
|
717 |
+
$meta_value = $this->field->escaped_value();
|
718 |
+
$allow = $this->field->args( 'allow' );
|
719 |
+
$input_type = ( 'url' == $allow || ( is_array( $allow ) && in_array( 'url', $allow ) ) )
|
720 |
+
? 'text' : 'hidden';
|
721 |
+
|
722 |
+
echo $this->input( array(
|
723 |
+
'type' => $input_type,
|
724 |
+
'class' => 'cmb_upload_file',
|
725 |
+
'size' => 45,
|
726 |
+
'desc' => '',
|
727 |
+
) ),
|
728 |
+
'<input class="cmb_upload_button button" type="button" value="'. __( 'Add or Upload File', 'cmb' ) .'" />',
|
729 |
+
$this->_desc( true );
|
730 |
+
|
731 |
+
$cached_id = $this->_id();
|
732 |
+
// Reset field args for attachment ID
|
733 |
+
$args = $this->field->args();
|
734 |
+
$args['id'] = $args['_id'] . '_id';
|
735 |
+
unset( $args['_id'], $args['_name'] );
|
736 |
+
|
737 |
+
// And get new field object
|
738 |
+
$this->field = new cmb_Meta_Box_field( $args, $this->field->group );
|
739 |
+
|
740 |
+
// Get ID value
|
741 |
+
$_id_value = $this->field->escaped_value( 'absint' );
|
742 |
+
|
743 |
+
// If there is no ID saved yet, try to get it from the url
|
744 |
+
if ( $meta_value && ! $_id_value ) {
|
745 |
+
$_id_value = cmb_Meta_Box::image_id_from_url( esc_url_raw( $meta_value ) );
|
746 |
+
}
|
747 |
+
|
748 |
+
echo $this->input( array(
|
749 |
+
'type' => 'hidden',
|
750 |
+
'class' => 'cmb_upload_file_id',
|
751 |
+
'value' => $_id_value,
|
752 |
+
'desc' => '',
|
753 |
+
) ),
|
754 |
+
'<div id="', $this->_id( '_status' ) ,'" class="cmb_media_status">';
|
755 |
+
if ( ! empty( $meta_value ) ) {
|
756 |
+
|
757 |
+
if ( $this->is_valid_img_ext( $meta_value ) ) {
|
758 |
+
echo '<div class="img_status">';
|
759 |
+
echo '<img style="max-width: 350px; width: 100%; height: auto;" src="', $meta_value, '" alt="" />';
|
760 |
+
echo '<p class="cmb_remove_wrapper"><a href="#" class="cmb_remove_file_button" rel="', $cached_id, '">'. __( 'Remove Image', 'cmb' ) .'</a></p>';
|
761 |
+
echo '</div>';
|
762 |
+
} else {
|
763 |
+
// $file_ext = $this->get_file_ext( $meta_value );
|
764 |
+
$parts = explode( '/', $meta_value );
|
765 |
+
for ( $i = 0; $i < count( $parts ); ++$i ) {
|
766 |
+
$title = $parts[$i];
|
767 |
+
}
|
768 |
+
echo __( 'File:', 'cmb' ), ' <strong>', $title, '</strong> (<a href="', $meta_value, '" target="_blank" rel="external">'. __( 'Download', 'cmb' ) .'</a> / <a href="#" class="cmb_remove_file_button" rel="', $cached_id, '">'. __( 'Remove', 'cmb' ) .'</a>)';
|
769 |
+
}
|
770 |
+
}
|
771 |
+
echo '</div>';
|
772 |
+
}
|
773 |
+
|
774 |
+
public function oembed() {
|
775 |
+
echo $this->input( array(
|
776 |
+
'class' => 'cmb_oembed regular-text',
|
777 |
+
'data-objectid' => $this->field->object_id,
|
778 |
+
'data-objecttype' => $this->field->object_type
|
779 |
+
) ),
|
780 |
+
'<p class="cmb-spinner spinner" style="display:none;"><img src="'. admin_url( '/images/wpspin_light.gif' ) .'" alt="spinner"/></p>',
|
781 |
+
'<div id="',$this->_id( '_status' ) ,'" class="cmb_media_status ui-helper-clearfix embed_wrap">';
|
782 |
+
|
783 |
+
if ( $meta_value = $this->field->escaped_value() ) {
|
784 |
+
echo cmb_Meta_Box_ajax::get_oembed( $meta_value, $this->field->object_id, array(
|
785 |
+
'object_type' => $this->field->object_type,
|
786 |
+
'oembed_args' => array( 'width' => '640' ),
|
787 |
+
'field_id' => $this->_id(),
|
788 |
+
) );
|
789 |
+
}
|
790 |
+
|
791 |
+
echo '</div>';
|
792 |
+
}
|
793 |
+
|
794 |
+
}
|
lib/cmb_metaboxes/init.php
CHANGED
@@ -1,1185 +1,1185 @@
|
|
1 |
-
<?php
|
2 |
-
/*
|
3 |
-
Script Name: Custom Metaboxes and Fields
|
4 |
-
Contributors: WebDevStudios (@webdevstudios / webdevstudios.com)
|
5 |
-
Justin Sternberg (@jtsternberg / dsgnwrks.pro)
|
6 |
-
Jared Atchison (@jaredatch / jaredatchison.com)
|
7 |
-
Bill Erickson (@billerickson / billerickson.net)
|
8 |
-
Andrew Norcross (@norcross / andrewnorcross.com)
|
9 |
-
Description: This will create metaboxes with custom fields that will blow your mind.
|
10 |
-
Version: 1.2.0
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Released under the GPL license
|
15 |
-
* http://www.opensource.org/licenses/gpl-license.php
|
16 |
-
*
|
17 |
-
* This is an add-on for WordPress
|
18 |
-
* http://wordpress.org/
|
19 |
-
*
|
20 |
-
* **********************************************************************
|
21 |
-
* This program is free software; you can redistribute it and/or modify
|
22 |
-
* it under the terms of the GNU General Public License as published by
|
23 |
-
* the Free Software Foundation; either version 2 of the License, or
|
24 |
-
* (at your option) any later version.
|
25 |
-
*
|
26 |
-
* This program is distributed in the hope that it will be useful,
|
27 |
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
28 |
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
29 |
-
* GNU General Public License for more details.
|
30 |
-
* **********************************************************************
|
31 |
-
*/
|
32 |
-
|
33 |
-
/************************************************************************
|
34 |
-
You should not edit the code below or things might explode!
|
35 |
-
*************************************************************************/
|
36 |
-
|
37 |
-
// Autoload helper classes
|
38 |
-
spl_autoload_register('cmb_Meta_Box::autoload_helpers');
|
39 |
-
|
40 |
-
$meta_boxes = array();
|
41 |
-
$meta_boxes = apply_filters( 'cmb_meta_boxes', $meta_boxes );
|
42 |
-
foreach ( $meta_boxes as $meta_box ) {
|
43 |
-
$my_box = new cmb_Meta_Box( $meta_box );
|
44 |
-
}
|
45 |
-
|
46 |
-
define( 'CMB_META_BOX_URL', cmb_Meta_Box::get_meta_box_url() );
|
47 |
-
|
48 |
-
/**
|
49 |
-
* Create meta boxes
|
50 |
-
*/
|
51 |
-
class cmb_Meta_Box {
|
52 |
-
|
53 |
-
/**
|
54 |
-
* Current version number
|
55 |
-
* @var string
|
56 |
-
* @since 1.0.0
|
57 |
-
*/
|
58 |
-
const CMB_VERSION = '1.2.0';
|
59 |
-
|
60 |
-
/**
|
61 |
-
* Metabox Config array
|
62 |
-
* @var array
|
63 |
-
* @since 0.9.0
|
64 |
-
*/
|
65 |
-
protected $_meta_box;
|
66 |
-
|
67 |
-
/**
|
68 |
-
* Metabox Defaults
|
69 |
-
* @var array
|
70 |
-
* @since 1.0.1
|
71 |
-
*/
|
72 |
-
protected static $mb_defaults = array(
|
73 |
-
'id' => '',
|
74 |
-
'title' => '',
|
75 |
-
'type' => '',
|
76 |
-
'pages' => array(), // Post type
|
77 |
-
'context' => 'normal',
|
78 |
-
'priority' => 'high',
|
79 |
-
'show_names' => true, // Show field names on the left
|
80 |
-
'show_on' => array( 'key' => false, 'value' => false ), // Specific post IDs or page templates to display this metabox
|
81 |
-
'cmb_styles' => true, // Include cmb bundled stylesheet
|
82 |
-
'fields' => array(),
|
83 |
-
);
|
84 |
-
|
85 |
-
/**
|
86 |
-
* Metabox Form ID
|
87 |
-
* @var string
|
88 |
-
* @since 0.9.4
|
89 |
-
*/
|
90 |
-
protected $form_id = 'post';
|
91 |
-
|
92 |
-
/**
|
93 |
-
* Current field config array
|
94 |
-
* @var array
|
95 |
-
* @since 1.0.0
|
96 |
-
*/
|
97 |
-
public static $field = array();
|
98 |
-
|
99 |
-
/**
|
100 |
-
* Object ID for metabox meta retrieving/saving
|
101 |
-
* @var int
|
102 |
-
* @since 1.0.0
|
103 |
-
*/
|
104 |
-
protected static $object_id = 0;
|
105 |
-
|
106 |
-
/**
|
107 |
-
* Type of object being saved. (e.g., post, user, or comment)
|
108 |
-
* @var string
|
109 |
-
* @since 1.0.0
|
110 |
-
*/
|
111 |
-
protected static $object_type = '';
|
112 |
-
|
113 |
-
/**
|
114 |
-
* Whether scripts/styles have been enqueued yet
|
115 |
-
* @var bool
|
116 |
-
* @since 1.0.0
|
117 |
-
*/
|
118 |
-
protected static $is_enqueued = false;
|
119 |
-
|
120 |
-
/**
|
121 |
-
* Whether CMB nonce has been added to the page. (oly add once)
|
122 |
-
* @var bool
|
123 |
-
* @since 1.2.0
|
124 |
-
*/
|
125 |
-
protected static $nonce_added = false;
|
126 |
-
|
127 |
-
/**
|
128 |
-
* Type of object specified by the metabox Config
|
129 |
-
* @var string
|
130 |
-
* @since 1.0.0
|
131 |
-
*/
|
132 |
-
protected static $mb_object_type = 'post';
|
133 |
-
|
134 |
-
/**
|
135 |
-
* Array of all options from manage-options metaboxes
|
136 |
-
* @var array
|
137 |
-
* @since 1.0.0
|
138 |
-
*/
|
139 |
-
protected static $options = array();
|
140 |
-
|
141 |
-
/**
|
142 |
-
* List of fields that are changed/updated on save
|
143 |
-
* @var array
|
144 |
-
* @since 1.1.0
|
145 |
-
*/
|
146 |
-
protected static $updated = array();
|
147 |
-
|
148 |
-
/**
|
149 |
-
* Get started
|
150 |
-
*/
|
151 |
-
function __construct( $meta_box ) {
|
152 |
-
|
153 |
-
$meta_box = self::set_mb_defaults( $meta_box );
|
154 |
-
|
155 |
-
$allow_frontend = apply_filters( 'cmb_allow_frontend', true, $meta_box );
|
156 |
-
|
157 |
-
if ( ! is_admin() && ! $allow_frontend )
|
158 |
-
return;
|
159 |
-
|
160 |
-
$this->_meta_box = $meta_box;
|
161 |
-
|
162 |
-
self::set_mb_type( $meta_box );
|
163 |
-
|
164 |
-
$types = wp_list_pluck( $meta_box['fields'], 'type' );
|
165 |
-
$upload = in_array( 'file', $types ) || in_array( 'file_list', $types );
|
166 |
-
|
167 |
-
global $pagenow;
|
168 |
-
|
169 |
-
$show_filters = 'cmb_Meta_Box_Show_Filters';
|
170 |
-
foreach ( get_class_methods( $show_filters ) as $filter ) {
|
171 |
-
add_filter( 'cmb_show_on', array( $show_filters, $filter ), 10, 2 );
|
172 |
-
}
|
173 |
-
|
174 |
-
// register our scripts and styles for cmb
|
175 |
-
add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts' ), 8 );
|
176 |
-
|
177 |
-
if ( self::get_object_type() == 'post' ) {
|
178 |
-
add_action( 'admin_menu', array( $this, 'add_metaboxes' ) );
|
179 |
-
add_action( 'add_attachment', array( $this, 'save_post' ) );
|
180 |
-
add_action( 'edit_attachment', array( $this, 'save_post' ) );
|
181 |
-
add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
|
182 |
-
add_action( 'admin_enqueue_scripts', array( $this, 'do_scripts' ) );
|
183 |
-
|
184 |
-
if ( $upload && in_array( $pagenow, array( 'page.php', 'page-new.php', 'post.php', 'post-new.php' ) ) ) {
|
185 |
-
add_action( 'admin_head', array( $this, 'add_post_enctype' ) );
|
186 |
-
}
|
187 |
-
|
188 |
-
}
|
189 |
-
if ( self::get_object_type() == 'user' ) {
|
190 |
-
|
191 |
-
$priority = 10;
|
192 |
-
if ( isset( $meta_box['priority'] ) ) {
|
193 |
-
if ( is_numeric( $meta_box['priority'] ) )
|
194 |
-
$priority = $meta_box['priority'];
|
195 |
-
elseif ( $meta_box['priority'] == 'high' )
|
196 |
-
$priority = 5;
|
197 |
-
elseif ( $meta_box['priority'] == 'low' )
|
198 |
-
$priority = 20;
|
199 |
-
}
|
200 |
-
add_action( 'show_user_profile', array( $this, 'user_metabox' ), $priority );
|
201 |
-
add_action( 'edit_user_profile', array( $this, 'user_metabox' ), $priority );
|
202 |
-
|
203 |
-
add_action( 'personal_options_update', array( $this, 'save_user' ) );
|
204 |
-
add_action( 'edit_user_profile_update', array( $this, 'save_user' ) );
|
205 |
-
if ( $upload && in_array( $pagenow, array( 'profile.php', 'user-edit.php' ) ) ) {
|
206 |
-
$this->form_id = 'your-profile';
|
207 |
-
add_action( 'admin_head', array( $this, 'add_post_enctype' ) );
|
208 |
-
}
|
209 |
-
}
|
210 |
-
|
211 |
-
}
|
212 |
-
|
213 |
-
/**
|
214 |
-
* Autoloads files with classes when needed
|
215 |
-
* @since 1.0.0
|
216 |
-
* @param string $class_name Name of the class being requested
|
217 |
-
*/
|
218 |
-
public static function autoload_helpers( $class_name ) {
|
219 |
-
if ( class_exists( $class_name, false ) )
|
220 |
-
return;
|
221 |
-
|
222 |
-
// for PHP versions < 5.3
|
223 |
-
$dir = dirname( __FILE__ );
|
224 |
-
|
225 |
-
$file = "$dir/helpers/$class_name.php";
|
226 |
-
if ( file_exists( $file ) )
|
227 |
-
@include( $file );
|
228 |
-
}
|
229 |
-
|
230 |
-
/**
|
231 |
-
* Registers scripts and styles for CMB
|
232 |
-
* @since 1.0.0
|
233 |
-
*/
|
234 |
-
public function register_scripts() {
|
235 |
-
|
236 |
-
// Should only be run once
|
237 |
-
if ( self::$is_enqueued )
|
238 |
-
return;
|
239 |
-
|
240 |
-
global $wp_version;
|
241 |
-
// Only use minified files if SCRIPT_DEBUG is off
|
242 |
-
$min = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
|
243 |
-
|
244 |
-
// scripts required for cmb
|
245 |
-
$scripts = array( 'jquery', 'jquery-ui-core', 'cmb-datepicker', /*'media-upload', */'cmb-timepicker' );
|
246 |
-
// styles required for cmb
|
247 |
-
$styles = array();
|
248 |
-
|
249 |
-
// if we're 3.5 or later, user wp-color-picker
|
250 |
-
if ( 3.5 <= $wp_version ) {
|
251 |
-
$scripts[] = 'wp-color-picker';
|
252 |
-
$styles[] = 'wp-color-picker';
|
253 |
-
if ( ! is_admin() ) {
|
254 |
-
// we need to register colorpicker on the front-end
|
255 |
-
wp_register_script( 'iris', admin_url( 'js/iris.min.js' ), array( 'jquery-ui-draggable', 'jquery-ui-slider', 'jquery-touch-punch' ), self::CMB_VERSION );
|
256 |
-
wp_register_script( 'wp-color-picker', admin_url( 'js/color-picker.min.js' ), array( 'iris' ), self::CMB_VERSION );
|
257 |
-
wp_localize_script( 'wp-color-picker', 'wpColorPickerL10n', array(
|
258 |
-
'clear' => __( 'Clear' ),
|
259 |
-
'defaultString' => __( 'Default' ),
|
260 |
-
'pick' => __( 'Select Color' ),
|
261 |
-
'current' => __( 'Current Color' ),
|
262 |
-
) );
|
263 |
-
}
|
264 |
-
} else {
|
265 |
-
// otherwise use the older 'farbtastic'
|
266 |
-
$scripts[] = 'farbtastic';
|
267 |
-
$styles[] = 'farbtastic';
|
268 |
-
}
|
269 |
-
wp_register_script( 'cmb-datepicker', CMB_META_BOX_URL . 'js/jquery.datePicker.min.js' );
|
270 |
-
wp_register_script( 'cmb-timepicker', CMB_META_BOX_URL . 'js/jquery.timePicker.min.js' );
|
271 |
-
wp_register_script( 'cmb-scripts', CMB_META_BOX_URL .'js/cmb'. $min .'.js', $scripts, self::CMB_VERSION );
|
272 |
-
|
273 |
-
wp_enqueue_media();
|
274 |
-
|
275 |
-
wp_localize_script( 'cmb-scripts', 'cmb_l10', apply_filters( 'cmb_localized_data', array(
|
276 |
-
'ajax_nonce' => wp_create_nonce( 'ajax_nonce' ),
|
277 |
-
'script_debug' => defined('SCRIPT_DEBUG') && SCRIPT_DEBUG,
|
278 |
-
'new_admin_style' => version_compare( $wp_version, '3.7', '>' ),
|
279 |
-
'object_type' => self::get_object_type(),
|
280 |
-
'upload_file' => 'Use this file',
|
281 |
-
'remove_image' => 'Remove Image',
|
282 |
-
'remove_file' => 'Remove',
|
283 |
-
'file' => 'File:',
|
284 |
-
'download' => 'Download',
|
285 |
-
'ajaxurl' => admin_url( '/admin-ajax.php' ),
|
286 |
-
'up_arrow' => '[ ↑ ] ',
|
287 |
-
'down_arrow' => ' [ ↓ ]',
|
288 |
-
'check_toggle' => __( 'Select / Deselect All', 'cmb' ),
|
289 |
-
) ) );
|
290 |
-
|
291 |
-
wp_register_style( 'cmb-styles', CMB_META_BOX_URL . 'style'. $min .'.css', $styles );
|
292 |
-
|
293 |
-
// Ok, we've enqueued our scripts/styles
|
294 |
-
self::$is_enqueued = true;
|
295 |
-
}
|
296 |
-
|
297 |
-
/**
|
298 |
-
* Enqueues scripts and styles for CMB
|
299 |
-
* @since 1.0.0
|
300 |
-
*/
|
301 |
-
public function do_scripts( $hook ) {
|
302 |
-
// only enqueue our scripts/styles on the proper pages
|
303 |
-
if ( $hook == 'post.php' || $hook == 'post-new.php' || $hook == 'page-new.php' || $hook == 'page.php' ) {
|
304 |
-
wp_enqueue_script( 'cmb-scripts' );
|
305 |
-
|
306 |
-
// default is to show cmb styles on post pages
|
307 |
-
if ( $this->_meta_box['cmb_styles'] )
|
308 |
-
wp_enqueue_style( 'cmb-styles' );
|
309 |
-
}
|
310 |
-
}
|
311 |
-
|
312 |
-
/**
|
313 |
-
* Add encoding attribute
|
314 |
-
*/
|
315 |
-
public function add_post_enctype() {
|
316 |
-
echo '
|
317 |
-
<script type="text/javascript">
|
318 |
-
jQuery(document).ready(function(){
|
319 |
-
jQuery("#'. $this->form_id .'").attr("enctype", "multipart/form-data");
|
320 |
-
jQuery("#'. $this->form_id .'").attr("encoding", "multipart/form-data");
|
321 |
-
});
|
322 |
-
</script>';
|
323 |
-
}
|
324 |
-
|
325 |
-
/**
|
326 |
-
* Add metaboxes (to 'post' object type)
|
327 |
-
*/
|
328 |
-
public function add_metaboxes() {
|
329 |
-
|
330 |
-
foreach ( $this->_meta_box['pages'] as $page ) {
|
331 |
-
if ( apply_filters( 'cmb_show_on', true, $this->_meta_box ) )
|
332 |
-
add_meta_box( $this->_meta_box['id'], $this->_meta_box['title'], array( $this, 'post_metabox' ), $page, $this->_meta_box['context'], $this->_meta_box['priority']) ;
|
333 |
-
}
|
334 |
-
}
|
335 |
-
|
336 |
-
/**
|
337 |
-
* Display metaboxes for a post object
|
338 |
-
* @since 1.0.0
|
339 |
-
*/
|
340 |
-
public function post_metabox() {
|
341 |
-
if ( ! $this->_meta_box )
|
342 |
-
return;
|
343 |
-
|
344 |
-
self::show_form( $this->_meta_box, get_the_ID(), 'post' );
|
345 |
-
|
346 |
-
}
|
347 |
-
|
348 |
-
/**
|
349 |
-
* Display metaboxes for a user object
|
350 |
-
* @since 1.0.0
|
351 |
-
*/
|
352 |
-
public function user_metabox() {
|
353 |
-
if ( ! $this->_meta_box )
|
354 |
-
return;
|
355 |
-
|
356 |
-
if ( 'user' != self::set_mb_type( $this->_meta_box ) )
|
357 |
-
return;
|
358 |
-
|
359 |
-
if ( ! apply_filters( 'cmb_show_on', true, $this->_meta_box ) )
|
360 |
-
return;
|
361 |
-
|
362 |
-
wp_enqueue_script( 'cmb-scripts' );
|
363 |
-
|
364 |
-
// default is to NOT show cmb styles on user profile page
|
365 |
-
if ( $this->_meta_box['cmb_styles'] != false )
|
366 |
-
wp_enqueue_style( 'cmb-styles' );
|
367 |
-
|
368 |
-
self::show_form( $this->_meta_box );
|
369 |
-
|
370 |
-
}
|
371 |
-
|
372 |
-
/**
|
373 |
-
* Loops through and displays fields
|
374 |
-
* @since 1.0.0
|
375 |
-
* @param array $meta_box Metabox config array
|
376 |
-
* @param int $object_id Object ID
|
377 |
-
* @param string $object_type Type of object being saved. (e.g., post, user, or comment)
|
378 |
-
*/
|
379 |
-
public static function show_form( $meta_box, $object_id = 0, $object_type = '' ) {
|
380 |
-
$meta_box = self::set_mb_defaults( $meta_box );
|
381 |
-
// Set/get type
|
382 |
-
$object_type = self::set_object_type( $object_type ? $object_type : self::set_mb_type( $meta_box ) );
|
383 |
-
// Set/get ID
|
384 |
-
$object_id = self::set_object_id( $object_id ? $object_id : self::get_object_id() );
|
385 |
-
|
386 |
-
// Add nonce only once per page.
|
387 |
-
if ( ! self::$nonce_added ) {
|
388 |
-
wp_nonce_field( self::nonce(), 'wp_meta_box_nonce', false, true );
|
389 |
-
self::$nonce_added = true;
|
390 |
-
}
|
391 |
-
|
392 |
-
// Use nonce for verification
|
393 |
-
echo "\n<!-- Begin CMB Fields -->\n";
|
394 |
-
do_action( 'cmb_before_table', $meta_box, $object_id, $object_type );
|
395 |
-
echo '<table class="form-table cmb_metabox">';
|
396 |
-
|
397 |
-
foreach ( $meta_box['fields'] as $field_args ) {
|
398 |
-
|
399 |
-
$field_args['context'] = $meta_box['context'];
|
400 |
-
|
401 |
-
if ( 'group' == $field_args['type'] ) {
|
402 |
-
|
403 |
-
if ( ! isset( $field_args['show_names'] ) ) {
|
404 |
-
$field_args['show_names'] = $meta_box['show_names'];
|
405 |
-
}
|
406 |
-
self::render_group( $field_args );
|
407 |
-
} else {
|
408 |
-
|
409 |
-
$field_args['show_names'] = $meta_box['show_names'];
|
410 |
-
// Render default fields
|
411 |
-
$field = new cmb_Meta_Box_field( $field_args );
|
412 |
-
$field->render_field();
|
413 |
-
}
|
414 |
-
}
|
415 |
-
echo '</table>';
|
416 |
-
do_action( 'cmb_after_table', $meta_box, $object_id, $object_type );
|
417 |
-
echo "\n<!-- End CMB Fields -->\n";
|
418 |
-
|
419 |
-
}
|
420 |
-
|
421 |
-
/**
|
422 |
-
* Render a repeatable group
|
423 |
-
*/
|
424 |
-
public static function render_group( $args ) {
|
425 |
-
if ( ! isset( $args['id'], $args['fields'] ) || ! is_array( $args['fields'] ) )
|
426 |
-
return;
|
427 |
-
|
428 |
-
$args['count'] = 0;
|
429 |
-
$field_group = new cmb_Meta_Box_field( $args );
|
430 |
-
$desc = $field_group->args( 'description' );
|
431 |
-
$label = $field_group->args( 'name' );
|
432 |
-
$sortable = $field_group->options( 'sortable' ) ? ' sortable' : '';
|
433 |
-
$group_val = (array) $field_group->value();
|
434 |
-
$nrows = count( $group_val );
|
435 |
-
$remove_disabled = $nrows <= 1 ? 'disabled="disabled" ' : '';
|
436 |
-
|
437 |
-
echo '<tr><td colspan="2"><table id="', $field_group->id(), '_repeat" class="repeatable-group'. $sortable .'" style="width:100%;">';
|
438 |
-
if ( $desc || $label ) {
|
439 |
-
echo '<tr><th>';
|
440 |
-
if ( $label )
|
441 |
-
echo '<h2 class="cmb-group-name">'. $label .'</h2>';
|
442 |
-
if ( $desc )
|
443 |
-
echo '<p class="cmb_metabox_description">'. $desc .'</p>';
|
444 |
-
echo '</th></tr>';
|
445 |
-
}
|
446 |
-
|
447 |
-
if ( ! empty( $group_val ) ) {
|
448 |
-
|
449 |
-
foreach ( $group_val as $iterator => $field_id ) {
|
450 |
-
self::render_group_row( $field_group, $remove_disabled );
|
451 |
-
}
|
452 |
-
} else {
|
453 |
-
self::render_group_row( $field_group, $remove_disabled );
|
454 |
-
}
|
455 |
-
|
456 |
-
echo '<tr><td><p class="add-row"><button data-selector="', $field_group->id() ,'_repeat" data-grouptitle="', $field_group->options( 'group_title' ) ,'" class="add-group-row button">'. $field_group->options( 'add_button' ) .'</button></p></td></tr>';
|
457 |
-
|
458 |
-
echo '</table></td></tr>';
|
459 |
-
|
460 |
-
}
|
461 |
-
|
462 |
-
public static function render_group_row( $field_group, $remove_disabled ) {
|
463 |
-
|
464 |
-
echo '
|
465 |
-
<tr class="repeatable-grouping" data-iterator="'. $field_group->count() .'">
|
466 |
-
<td>
|
467 |
-
<table class="cmb-nested-table" style="width: 100%;">';
|
468 |
-
if ( $field_group->options( 'group_title' ) ) {
|
469 |
-
echo '
|
470 |
-
<tr class="cmb-group-title">
|
471 |
-
<th colspan="2">
|
472 |
-
', sprintf( '<h4>%1$s</h4>', $field_group->replace_hash( $field_group->options( 'group_title' ) ) ), '
|
473 |
-
<th>
|
474 |
-
</tr>
|
475 |
-
';
|
476 |
-
}
|
477 |
-
// Render repeatable group fields
|
478 |
-
foreach ( array_values( $field_group->args( 'fields' ) ) as $field_args ) {
|
479 |
-
$field_args['show_names'] = $field_group->args( 'show_names' );
|
480 |
-
$field_args['context'] = $field_group->args( 'context' );
|
481 |
-
$field = new cmb_Meta_Box_field( $field_args, $field_group );
|
482 |
-
$field->render_field();
|
483 |
-
}
|
484 |
-
echo '
|
485 |
-
<tr>
|
486 |
-
<td class="remove-row" colspan="2">
|
487 |
-
<button '. $remove_disabled .'data-selector="'. $field_group->id() .'_repeat" class="button remove-group-row alignright">'. $field_group->options( 'remove_button' ) .'</button>
|
488 |
-
</td>
|
489 |
-
</tr>
|
490 |
-
</table>
|
491 |
-
</td>
|
492 |
-
</tr>
|
493 |
-
';
|
494 |
-
|
495 |
-
$field_group->args['count']++;
|
496 |
-
}
|
497 |
-
|
498 |
-
/**
|
499 |
-
* Save data from metabox
|
500 |
-
*/
|
501 |
-
public function save_post( $post_id, $post = false ) {
|
502 |
-
|
503 |
-
$post_type = $post ? $post->post_type : get_post_type( $post_id );
|
504 |
-
|
505 |
-
// check permissions
|
506 |
-
if (
|
507 |
-
// check nonce
|
508 |
-
! isset( $_POST['wp_meta_box_nonce'] )
|
509 |
-
|| ! wp_verify_nonce( $_POST['wp_meta_box_nonce'], self::nonce() )
|
510 |
-
// check if autosave
|
511 |
-
|| defined('DOING_AUTOSAVE' ) && DOING_AUTOSAVE
|
512 |
-
// check user editing permissions
|
513 |
-
|| ( 'page' == $_POST['post_type'] && ! current_user_can( 'edit_page', $post_id ) )
|
514 |
-
|| ! current_user_can( 'edit_post', $post_id )
|
515 |
-
// get the metabox post_types & compare it to this post_type
|
516 |
-
|| ! in_array( $post_type, $this->_meta_box['pages'] )
|
517 |
-
)
|
518 |
-
return $post_id;
|
519 |
-
|
520 |
-
self::save_fields( $this->_meta_box, $post_id, 'post' );
|
521 |
-
}
|
522 |
-
|
523 |
-
/**
|
524 |
-
* Save data from metabox
|
525 |
-
*/
|
526 |
-
public function save_user( $user_id ) {
|
527 |
-
|
528 |
-
// check permissions
|
529 |
-
// @todo more hardening?
|
530 |
-
if (
|
531 |
-
// check nonce
|
532 |
-
! isset( $_POST['wp_meta_box_nonce'] )
|
533 |
-
|| ! wp_verify_nonce( $_POST['wp_meta_box_nonce'], self::nonce() )
|
534 |
-
)
|
535 |
-
return $user_id;
|
536 |
-
|
537 |
-
self::save_fields( $this->_meta_box, $user_id, 'user' );
|
538 |
-
}
|
539 |
-
|
540 |
-
/**
|
541 |
-
* Loops through and saves field data
|
542 |
-
* @since 1.0.0
|
543 |
-
* @param array $meta_box Metabox config array
|
544 |
-
* @param int $object_id Object ID
|
545 |
-
* @param string $object_type Type of object being saved. (e.g., post, user, or comment)
|
546 |
-
*/
|
547 |
-
public static function save_fields( $meta_box, $object_id, $object_type = '' ) {
|
548 |
-
$meta_box = self::set_mb_defaults( $meta_box );
|
549 |
-
|
550 |
-
$meta_box['show_on'] = empty( $meta_box['show_on'] ) ? array( 'key' => false, 'value' => false ) : $meta_box['show_on'];
|
551 |
-
|
552 |
-
self::set_object_id( $object_id );
|
553 |
-
// Set/get type
|
554 |
-
$object_type = self::set_object_type( $object_type ? $object_type : self::set_mb_type( $meta_box ) );
|
555 |
-
|
556 |
-
if ( ! apply_filters( 'cmb_show_on', true, $meta_box ) )
|
557 |
-
return;
|
558 |
-
|
559 |
-
// save field ids of those that are updated
|
560 |
-
self::$updated = array();
|
561 |
-
|
562 |
-
foreach ( $meta_box['fields'] as $field_args ) {
|
563 |
-
|
564 |
-
if ( 'group' == $field_args['type'] ) {
|
565 |
-
self::save_group( $field_args );
|
566 |
-
} else {
|
567 |
-
// Save default fields
|
568 |
-
$field = new cmb_Meta_Box_field( $field_args );
|
569 |
-
self::save_field( self::sanitize_field( $field ), $field );
|
570 |
-
}
|
571 |
-
|
572 |
-
}
|
573 |
-
|
574 |
-
// If options page, save the updated options
|
575 |
-
if ( $object_type == 'options-page' )
|
576 |
-
self::save_option( $object_id );
|
577 |
-
|
578 |
-
do_action( "cmb_save_{$object_type}_fields", $object_id, $meta_box['id'], self::$updated, $meta_box );
|
579 |
-
|
580 |
-
}
|
581 |
-
|
582 |
-
/**
|
583 |
-
* Save a repeatable group
|
584 |
-
*/
|
585 |
-
public static function save_group( $args ) {
|
586 |
-
if ( ! isset( $args['id'], $args['fields'], $_POST[ $args['id'] ] ) || ! is_array( $args['fields'] ) )
|
587 |
-
return;
|
588 |
-
|
589 |
-
$field_group = new cmb_Meta_Box_field( $args );
|
590 |
-
$base_id = $field_group->id();
|
591 |
-
$old = $field_group->get_data();
|
592 |
-
$group_vals = $_POST[ $base_id ];
|
593 |
-
$saved = array();
|
594 |
-
$is_updated = false;
|
595 |
-
$field_group->index = 0;
|
596 |
-
|
597 |
-
// $group_vals[0]['color'] = '333';
|
598 |
-
foreach ( array_values( $field_group->fields() ) as $field_args ) {
|
599 |
-
$field = new cmb_Meta_Box_field( $field_args, $field_group );
|
600 |
-
$sub_id = $field->id( true );
|
601 |
-
|
602 |
-
foreach ( (array) $group_vals as $field_group->index => $post_vals ) {
|
603 |
-
|
604 |
-
// Get value
|
605 |
-
$new_val = isset( $group_vals[ $field_group->index ][ $sub_id ] )
|
606 |
-
? $group_vals[ $field_group->index ][ $sub_id ]
|
607 |
-
: false;
|
608 |
-
|
609 |
-
// Sanitize
|
610 |
-
$new_val = self::sanitize_field( $field, $new_val, $field_group->index );
|
611 |
-
|
612 |
-
if ( 'file' == $field->type() && is_array( $new_val ) ) {
|
613 |
-
// Add image ID to the array stack
|
614 |
-
$saved[ $field_group->index ][ $new_val['field_id'] ] = $new_val['attach_id'];
|
615 |
-
// Reset var to url string
|
616 |
-
$new_val = $new_val['url'];
|
617 |
-
}
|
618 |
-
|
619 |
-
// Get old value
|
620 |
-
$old_val = is_array( $old ) && isset( $old[ $field_group->index ][ $sub_id ] )
|
621 |
-
? $old[ $field_group->index ][ $sub_id ]
|
622 |
-
: false;
|
623 |
-
|
624 |
-
$is_updated = ( ! empty( $new_val ) && $new_val != $old_val );
|
625 |
-
$is_removed = ( empty( $new_val ) && ! empty( $old_val ) );
|
626 |
-
// Compare values and add to `$updated` array
|
627 |
-
if ( $is_updated || $is_removed )
|
628 |
-
self::$updated[] = $base_id .'::'. $field_group->index .'::'. $sub_id;
|
629 |
-
|
630 |
-
// Add to `$saved` array
|
631 |
-
$saved[ $field_group->index ][ $sub_id ] = $new_val;
|
632 |
-
|
633 |
-
}
|
634 |
-
$saved[ $field_group->index ] = array_filter( $saved[ $field_group->index ] );
|
635 |
-
}
|
636 |
-
$saved = array_filter( $saved );
|
637 |
-
|
638 |
-
$field_group->update_data( $saved, true );
|
639 |
-
}
|
640 |
-
|
641 |
-
public static function sanitize_field( $field, $new_value = null ) {
|
642 |
-
|
643 |
-
$new_value = null !== $new_value
|
644 |
-
? $new_value
|
645 |
-
: ( isset( $_POST[ $field->id( true ) ] ) ? $_POST[ $field->id( true ) ] : null );
|
646 |
-
|
647 |
-
if ( $field->args( 'repeatable' ) && is_array( $new_value ) ) {
|
648 |
-
// Remove empties
|
649 |
-
$new_value = array_filter( $new_value );
|
650 |
-
}
|
651 |
-
|
652 |
-
// Check if this metabox field has a registered validation callback, or perform default sanitization
|
653 |
-
return $field->sanitization_cb( $new_value );
|
654 |
-
}
|
655 |
-
|
656 |
-
public static function save_field( $new_value, $field ) {
|
657 |
-
$name = $field->id();
|
658 |
-
$old = $field->get_data();
|
659 |
-
|
660 |
-
// if ( $field->args( 'multiple' ) && ! $field->args( 'repeatable' ) && ! $field->group ) {
|
661 |
-
// $field->remove_data();
|
662 |
-
// if ( ! empty( $new_value ) ) {
|
663 |
-
// foreach ( $new_value as $add_new ) {
|
664 |
-
// self::$updated[] = $name;
|
665 |
-
// $field->update_data( $add_new, $name, false );
|
666 |
-
// }
|
667 |
-
// }
|
668 |
-
// } else
|
669 |
-
if ( ! empty( $new_value ) && $new_value != $old ) {
|
670 |
-
self::$updated[] = $name;
|
671 |
-
return $field->update_data( $new_value );
|
672 |
-
} elseif ( empty( $new_value ) ) {
|
673 |
-
if ( ! empty( $old ) )
|
674 |
-
self::$updated[] = $name;
|
675 |
-
return $field->remove_data();
|
676 |
-
}
|
677 |
-
}
|
678 |
-
|
679 |
-
/**
|
680 |
-
* Get object id from global space if no id is provided
|
681 |
-
* @since 1.0.0
|
682 |
-
* @param integer $object_id Object ID
|
683 |
-
* @return integer $object_id Object ID
|
684 |
-
*/
|
685 |
-
public static function get_object_id( $object_id = 0 ) {
|
686 |
-
|
687 |
-
if ( $object_id )
|
688 |
-
return $object_id;
|
689 |
-
|
690 |
-
if ( self::$object_id )
|
691 |
-
return self::$object_id;
|
692 |
-
|
693 |
-
// Try to get our object ID from the global space
|
694 |
-
switch ( self::get_object_type() ) {
|
695 |
-
case 'user':
|
696 |
-
$object_id = isset( $GLOBALS['user_ID'] ) ? $GLOBALS['user_ID'] : $object_id;
|
697 |
-
$object_id = isset( $_REQUEST['user_id'] ) ? $_REQUEST['user_id'] : $object_id;
|
698 |
-
break;
|
699 |
-
|
700 |
-
default:
|
701 |
-
$object_id = isset( $GLOBALS['post']->ID ) ? $GLOBALS['post']->ID : $object_id;
|
702 |
-
$object_id = isset( $_REQUEST['post'] ) ? $_REQUEST['post'] : $object_id;
|
703 |
-
break;
|
704 |
-
}
|
705 |
-
|
706 |
-
// reset to id or 0
|
707 |
-
self::set_object_id( $object_id ? $object_id : 0 );
|
708 |
-
|
709 |
-
return self::$object_id;
|
710 |
-
}
|
711 |
-
|
712 |
-
/**
|
713 |
-
* Explicitly Set object id
|
714 |
-
* @since 1.0.0
|
715 |
-
* @param integer $object_id Object ID
|
716 |
-
* @return integer $object_id Object ID
|
717 |
-
*/
|
718 |
-
public static function set_object_id( $object_id ) {
|
719 |
-
return self::$object_id = $object_id;
|
720 |
-
}
|
721 |
-
|
722 |
-
/**
|
723 |
-
* Sets the $object_type based on metabox settings
|
724 |
-
* @since 1.0.0
|
725 |
-
* @param array|string $meta_box Metabox config array or explicit setting
|
726 |
-
* @return string Object type
|
727 |
-
*/
|
728 |
-
public static function set_mb_type( $meta_box ) {
|
729 |
-
|
730 |
-
if ( is_string( $meta_box ) ) {
|
731 |
-
self::$mb_object_type = $meta_box;
|
732 |
-
return self::get_mb_type();
|
733 |
-
}
|
734 |
-
|
735 |
-
if ( ! isset( $meta_box['pages'] ) )
|
736 |
-
return self::get_mb_type();
|
737 |
-
|
738 |
-
$type = false;
|
739 |
-
// check if 'pages' is a string
|
740 |
-
if ( self::is_options_page_mb( $meta_box ) )
|
741 |
-
$type = 'options-page';
|
742 |
-
// check if 'pages' is a string
|
743 |
-
elseif ( is_string( $meta_box['pages'] ) )
|
744 |
-
$type = $meta_box['pages'];
|
745 |
-
// if it's an array of one, extract it
|
746 |
-
elseif ( is_array( $meta_box['pages'] ) && count( $meta_box['pages'] === 1 ) )
|
747 |
-
$type = is_string( end( $meta_box['pages'] ) ) ? end( $meta_box['pages'] ) : false;
|
748 |
-
|
749 |
-
if ( !$type )
|
750 |
-
return self::get_mb_type();
|
751 |
-
|
752 |
-
// Get our object type
|
753 |
-
if ( 'user' == $type )
|
754 |
-
self::$mb_object_type = 'user';
|
755 |
-
elseif ( 'comment' == $type )
|
756 |
-
self::$mb_object_type = 'comment';
|
757 |
-
elseif ( 'options-page' == $type )
|
758 |
-
self::$mb_object_type = 'options-page';
|
759 |
-
else
|
760 |
-
self::$mb_object_type = 'post';
|
761 |
-
|
762 |
-
return self::get_mb_type();
|
763 |
-
}
|
764 |
-
|
765 |
-
/**
|
766 |
-
* Determines if metabox is for an options page
|
767 |
-
* @since 1.0.1
|
768 |
-
* @param array $meta_box Metabox config array
|
769 |
-
* @return boolean True/False
|
770 |
-
*/
|
771 |
-
public static function is_options_page_mb( $meta_box ) {
|
772 |
-
return ( isset( $meta_box['show_on']['key'] ) && 'options-page' === $meta_box['show_on']['key'] );
|
773 |
-
}
|
774 |
-
|
775 |
-
/**
|
776 |
-
* Returns the object type
|
777 |
-
* @since 1.0.0
|
778 |
-
* @return string Object type
|
779 |
-
*/
|
780 |
-
public static function get_object_type() {
|
781 |
-
if ( self::$object_type )
|
782 |
-
return self::$object_type;
|
783 |
-
|
784 |
-
global $pagenow;
|
785 |
-
|
786 |
-
if (
|
787 |
-
$pagenow == 'user-edit.php'
|
788 |
-
|| $pagenow == 'profile.php'
|
789 |
-
)
|
790 |
-
self::set_object_type( 'user' );
|
791 |
-
|
792 |
-
elseif (
|
793 |
-
$pagenow == 'edit-comments.php'
|
794 |
-
|| $pagenow == 'comment.php'
|
795 |
-
)
|
796 |
-
self::set_object_type( 'comment' );
|
797 |
-
else
|
798 |
-
self::set_object_type( 'post' );
|
799 |
-
|
800 |
-
return self::$object_type;
|
801 |
-
}
|
802 |
-
|
803 |
-
/**
|
804 |
-
* Sets the object type
|
805 |
-
* @since 1.0.0
|
806 |
-
* @return string Object type
|
807 |
-
*/
|
808 |
-
public static function set_object_type( $object_type ) {
|
809 |
-
return self::$object_type = $object_type;
|
810 |
-
}
|
811 |
-
|
812 |
-
/**
|
813 |
-
* Returns the object type
|
814 |
-
* @since 1.0.0
|
815 |
-
* @return string Object type
|
816 |
-
*/
|
817 |
-
public static function get_mb_type() {
|
818 |
-
return self::$mb_object_type;
|
819 |
-
}
|
820 |
-
|
821 |
-
/**
|
822 |
-
* Returns the nonce value for wp_meta_box_nonce
|
823 |
-
* @since 1.0.0
|
824 |
-
* @return string Nonce value
|
825 |
-
*/
|
826 |
-
public static function nonce() {
|
827 |
-
return basename( __FILE__ );
|
828 |
-
}
|
829 |
-
|
830 |
-
/**
|
831 |
-
* Defines the url which is used to load local resources.
|
832 |
-
* This may need to be filtered for local Window installations.
|
833 |
-
* If resources do not load, please check the wiki for details.
|
834 |
-
* @since 1.0.1
|
835 |
-
* @return string URL to CMB resources
|
836 |
-
*/
|
837 |
-
public static function get_meta_box_url() {
|
838 |
-
|
839 |
-
if ( strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN' ) {
|
840 |
-
// Windows
|
841 |
-
$content_dir = str_replace( '/', DIRECTORY_SEPARATOR, WP_CONTENT_DIR );
|
842 |
-
$content_url = str_replace( $content_dir, WP_CONTENT_URL, dirname(__FILE__) );
|
843 |
-
$cmb_url = str_replace( DIRECTORY_SEPARATOR, '/', $content_url );
|
844 |
-
|
845 |
-
} else {
|
846 |
-
$cmb_url = str_replace(
|
847 |
-
array(WP_CONTENT_DIR, WP_PLUGIN_DIR),
|
848 |
-
array(WP_CONTENT_URL, WP_PLUGIN_URL),
|
849 |
-
dirname( __FILE__ )
|
850 |
-
);
|
851 |
-
}
|
852 |
-
|
853 |
-
return trailingslashit( apply_filters('cmb_meta_box_url', $cmb_url ) );
|
854 |
-
}
|
855 |
-
|
856 |
-
/**
|
857 |
-
* Fills in empty metabox parameters with defaults
|
858 |
-
* @since 1.0.1
|
859 |
-
* @param array $meta_box Metabox config array
|
860 |
-
* @return array Modified Metabox config array
|
861 |
-
*/
|
862 |
-
public static function set_mb_defaults( $meta_box ) {
|
863 |
-
return wp_parse_args( $meta_box, self::$mb_defaults );
|
864 |
-
}
|
865 |
-
|
866 |
-
/**
|
867 |
-
* Removes an option from an option array
|
868 |
-
* @since 1.0.1
|
869 |
-
* @param string $option_key Option key
|
870 |
-
* @param string $field_id Option array field key
|
871 |
-
* @return array Modified options
|
872 |
-
*/
|
873 |
-
public static function remove_option( $option_key, $field_id ) {
|
874 |
-
|
875 |
-
self::$options[ $option_key ] = ! isset( self::$options[ $option_key ] ) || empty( self::$options[ $option_key ] ) ? self::_get_option( $option_key ) : self::$options[ $option_key ];
|
876 |
-
|
877 |
-
if ( isset( self::$options[ $option_key ][ $field_id ] ) )
|
878 |
-
unset( self::$options[ $option_key ][ $field_id ] );
|
879 |
-
|
880 |
-
return self::$options[ $option_key ];
|
881 |
-
}
|
882 |
-
|
883 |
-
/**
|
884 |
-
* Retrieves an option from an option array
|
885 |
-
* @since 1.0.1
|
886 |
-
* @param string $option_key Option key
|
887 |
-
* @param string $field_id Option array field key
|
888 |
-
* @return array Options array or specific field
|
889 |
-
*/
|
890 |
-
public static function get_option( $option_key, $field_id = '' ) {
|
891 |
-
|
892 |
-
self::$options[ $option_key ] = ! isset( self::$options[ $option_key ] ) || empty( self::$options[ $option_key ] ) ? self::_get_option( $option_key ) : self::$options[ $option_key ];
|
893 |
-
|
894 |
-
if ( $field_id ) {
|
895 |
-
return isset( self::$options[ $option_key ][ $field_id ] ) ? self::$options[ $option_key ][ $field_id ] : false;
|
896 |
-
}
|
897 |
-
|
898 |
-
return self::$options[ $option_key ];
|
899 |
-
}
|
900 |
-
|
901 |
-
/**
|
902 |
-
* Updates Option data
|
903 |
-
* @since 1.0.1
|
904 |
-
* @param string $option_key Option key
|
905 |
-
* @param string $field_id Option array field key
|
906 |
-
* @param mixed $value Value to update data with
|
907 |
-
* @param bool $single Whether data should be an array
|
908 |
-
* @return array Modified options
|
909 |
-
*/
|
910 |
-
public static function update_option( $option_key, $field_id, $value, $single = true ) {
|
911 |
-
|
912 |
-
if ( ! $single ) {
|
913 |
-
// If multiple, add to array
|
914 |
-
self::$options[ $option_key ][ $field_id ][] = $value;
|
915 |
-
} else {
|
916 |
-
self::$options[ $option_key ][ $field_id ] = $value;
|
917 |
-
}
|
918 |
-
|
919 |
-
return self::$options[ $option_key ];
|
920 |
-
}
|
921 |
-
|
922 |
-
/**
|
923 |
-
* Retrieve option value based on name of option.
|
924 |
-
* @uses apply_filters() Calls 'cmb_override_option_get_$option_key' hook to allow
|
925 |
-
* overwriting the option value to be retrieved.
|
926 |
-
*
|
927 |
-
* @since 1.0.1
|
928 |
-
* @param string $option Name of option to retrieve. Expected to not be SQL-escaped.
|
929 |
-
* @param mixed $default Optional. Default value to return if the option does not exist.
|
930 |
-
* @return mixed Value set for the option.
|
931 |
-
*/
|
932 |
-
public static function _get_option( $option_key, $default = false ) {
|
933 |
-
|
934 |
-
$test_get = apply_filters( "cmb_override_option_get_$option_key", 'cmb_no_override_option_get', $default );
|
935 |
-
|
936 |
-
if ( $test_get !== 'cmb_no_override_option_get' )
|
937 |
-
return $test_get;
|
938 |
-
|
939 |
-
// If no override, get the option
|
940 |
-
return get_option( $option_key, $default );
|
941 |
-
}
|
942 |
-
|
943 |
-
/**
|
944 |
-
* Saves the option array
|
945 |
-
* Needs to be run after finished using remove/update_option
|
946 |
-
* @uses apply_filters() Calls 'cmb_override_option_save_$option_key' hook to allow
|
947 |
-
* overwriting the option value to be stored.
|
948 |
-
*
|
949 |
-
* @since 1.0.1
|
950 |
-
* @param string $option_key Option key
|
951 |
-
* @return boolean Success/Failure
|
952 |
-
*/
|
953 |
-
public static function save_option( $option_key ) {
|
954 |
-
|
955 |
-
$to_save = self::get_option( $option_key );
|
956 |
-
|
957 |
-
$test_save = apply_filters( "cmb_override_option_save_$option_key", 'cmb_no_override_option_save', $to_save );
|
958 |
-
|
959 |
-
if ( $test_save !== 'cmb_no_override_option_save' )
|
960 |
-
return $test_save;
|
961 |
-
|
962 |
-
// If no override, update the option
|
963 |
-
return update_option( $option_key, $to_save );
|
964 |
-
}
|
965 |
-
|
966 |
-
/**
|
967 |
-
* Utility method that returns a timezone string representing the default timezone for the site.
|
968 |
-
*
|
969 |
-
* Roughly copied from WordPress, as get_option('timezone_string') will return
|
970 |
-
* and empty string if no value has beens set on the options page.
|
971 |
-
* A timezone string is required by the wp_timezone_choice() used by the
|
972 |
-
* select_timezone field.
|
973 |
-
*
|
974 |
-
* @since 1.0.0
|
975 |
-
* @return string Timezone string
|
976 |
-
*/
|
977 |
-
public static function timezone_string() {
|
978 |
-
$current_offset = get_option( 'gmt_offset' );
|
979 |
-
$tzstring = get_option( 'timezone_string' );
|
980 |
-
|
981 |
-
if ( empty( $tzstring ) ) { // Create a UTC+- zone if no timezone string exists
|
982 |
-
if ( 0 == $current_offset )
|
983 |
-
$tzstring = 'UTC+0';
|
984 |
-
elseif ( $current_offset < 0 )
|
985 |
-
$tzstring = 'UTC' . $current_offset;
|
986 |
-
else
|
987 |
-
$tzstring = 'UTC+' . $current_offset;
|
988 |
-
}
|
989 |
-
|
990 |
-
return $tzstring;
|
991 |
-
}
|
992 |
-
|
993 |
-
/**
|
994 |
-
* Utility method that returns time string offset by timezone
|
995 |
-
* @since 1.0.0
|
996 |
-
* @param string $tzstring Time string
|
997 |
-
* @return string Offset time string
|
998 |
-
*/
|
999 |
-
public static function timezone_offset( $tzstring ) {
|
1000 |
-
if ( ! empty( $tzstring ) && is_string( $tzstring ) ) {
|
1001 |
-
if ( substr( $tzstring, 0, 3 ) === 'UTC' ) {
|
1002 |
-
$tzstring = str_replace( array( ':15',':30',':45' ), array( '.25','.5','.75' ), $tzstring );
|
1003 |
-
return intval( floatval( substr( $tzstring, 3 ) ) * HOUR_IN_SECONDS );
|
1004 |
-
}
|
1005 |
-
|
1006 |
-
$date_time_zone_selected = new DateTimeZone( $tzstring );
|
1007 |
-
$tz_offset = timezone_offset_get( $date_time_zone_selected, date_create() );
|
1008 |
-
|
1009 |
-
return $tz_offset;
|
1010 |
-
}
|
1011 |
-
|
1012 |
-
return 0;
|
1013 |
-
}
|
1014 |
-
|
1015 |
-
/**
|
1016 |
-
* Utility method that attempts to get an attachment's ID by it's url
|
1017 |
-
* @since 1.0.0
|
1018 |
-
* @param string $img_url Attachment url
|
1019 |
-
* @return mixed Attachment ID or false
|
1020 |
-
*/
|
1021 |
-
public static function image_id_from_url( $img_url ) {
|
1022 |
-
global $wpdb;
|
1023 |
-
|
1024 |
-
$img_url = esc_url_raw( $img_url );
|
1025 |
-
// Get just the file name
|
1026 |
-
if ( false !== strpos( $img_url, '/' ) ) {
|
1027 |
-
$explode = explode( '/', $img_url );
|
1028 |
-
$img_url = end( $explode );
|
1029 |
-
}
|
1030 |
-
|
1031 |
-
// And search for a fuzzy match of the file name
|
1032 |
-
$attachment = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE guid LIKE '%%%s%%' LIMIT 1;", $img_url ) );
|
1033 |
-
|
1034 |
-
// If we found an attachement ID, return it
|
1035 |
-
if ( !empty( $attachment ) && is_array( $attachment ) )
|
1036 |
-
return $attachment[0];
|
1037 |
-
|
1038 |
-
// No luck
|
1039 |
-
return false;
|
1040 |
-
}
|
1041 |
-
|
1042 |
-
}
|
1043 |
-
|
1044 |
-
// Handle oembed Ajax
|
1045 |
-
add_action( 'wp_ajax_cmb_oembed_handler', array( 'cmb_Meta_Box_ajax', 'oembed_handler' ) );
|
1046 |
-
add_action( 'wp_ajax_nopriv_cmb_oembed_handler', array( 'cmb_Meta_Box_ajax', 'oembed_handler' ) );
|
1047 |
-
|
1048 |
-
/**
|
1049 |
-
* A helper function to get an option from a CMB options array
|
1050 |
-
* @since 1.0.1
|
1051 |
-
* @param string $option_key Option key
|
1052 |
-
* @param string $field_id Option array field key
|
1053 |
-
* @return array Options array or specific field
|
1054 |
-
*/
|
1055 |
-
function cmb_get_option( $option_key, $field_id = '' ) {
|
1056 |
-
return cmb_Meta_Box::get_option( $option_key, $field_id );
|
1057 |
-
}
|
1058 |
-
|
1059 |
-
/**
|
1060 |
-
* Get a CMB field object.
|
1061 |
-
* @since 1.1.0
|
1062 |
-
* @param array $field_args Field arguments
|
1063 |
-
* @param int $object_id Object ID
|
1064 |
-
* @param string $object_type Type of object being saved. (e.g., post, user, or comment)
|
1065 |
-
* @return object cmb_Meta_Box_field object
|
1066 |
-
*/
|
1067 |
-
function cmb_get_field( $field_args, $object_id = 0, $object_type = 'post' ) {
|
1068 |
-
// Default to the loop post ID
|
1069 |
-
$object_id = $object_id ? $object_id : get_the_ID();
|
1070 |
-
cmb_Meta_Box::set_object_id( $object_id );
|
1071 |
-
cmb_Meta_Box::set_object_type( $object_type );
|
1072 |
-
// Send back field object
|
1073 |
-
return new cmb_Meta_Box_field( $field_args );
|
1074 |
-
}
|
1075 |
-
|
1076 |
-
/**
|
1077 |
-
* Get a field's value.
|
1078 |
-
* @since 1.1.0
|
1079 |
-
* @param array $field_args Field arguments
|
1080 |
-
* @param int $object_id Object ID
|
1081 |
-
* @param string $object_type Type of object being saved. (e.g., post, user, comment, or options-page)
|
1082 |
-
* @return mixed Maybe escaped value
|
1083 |
-
*/
|
1084 |
-
function cmb_get_field_value( $field_args, $object_id = 0, $object_type = 'post' ) {
|
1085 |
-
$field = cmb_get_field( $field_args, $object_id, $object_type );
|
1086 |
-
return $field->escaped_value();
|
1087 |
-
}
|
1088 |
-
|
1089 |
-
/**
|
1090 |
-
* Loop and output multiple metaboxes
|
1091 |
-
* @since 1.0.0
|
1092 |
-
* @param array $meta_boxes Metaboxes config array
|
1093 |
-
* @param int $object_id Object ID
|
1094 |
-
*/
|
1095 |
-
function cmb_print_metaboxes( $meta_boxes, $object_id ) {
|
1096 |
-
foreach ( (array) $meta_boxes as $meta_box ) {
|
1097 |
-
cmb_print_metabox( $meta_box, $object_id );
|
1098 |
-
}
|
1099 |
-
}
|
1100 |
-
|
1101 |
-
/**
|
1102 |
-
* Output a metabox
|
1103 |
-
* @since 1.0.0
|
1104 |
-
* @param array $meta_box Metabox config array
|
1105 |
-
* @param int $object_id Object ID
|
1106 |
-
*/
|
1107 |
-
function cmb_print_metabox( $meta_box, $object_id ) {
|
1108 |
-
$cmb = new cmb_Meta_Box( $meta_box );
|
1109 |
-
if ( $cmb ) {
|
1110 |
-
|
1111 |
-
cmb_Meta_Box::set_object_id( $object_id );
|
1112 |
-
|
1113 |
-
if ( ! wp_script_is( 'cmb-scripts', 'registered' ) )
|
1114 |
-
$cmb->register_scripts();
|
1115 |
-
|
1116 |
-
wp_enqueue_script( 'cmb-scripts' );
|
1117 |
-
|
1118 |
-
// default is to show cmb styles
|
1119 |
-
if ( $meta_box['cmb_styles'] != false )
|
1120 |
-
wp_enqueue_style( 'cmb-styles' );
|
1121 |
-
|
1122 |
-
cmb_Meta_Box::show_form( $meta_box );
|
1123 |
-
}
|
1124 |
-
|
1125 |
-
}
|
1126 |
-
|
1127 |
-
/**
|
1128 |
-
* Saves a particular metabox's fields
|
1129 |
-
* @since 1.0.0
|
1130 |
-
* @param array $meta_box Metabox config array
|
1131 |
-
* @param int $object_id Object ID
|
1132 |
-
*/
|
1133 |
-
function cmb_save_metabox_fields( $meta_box, $object_id ) {
|
1134 |
-
cmb_Meta_Box::save_fields( $meta_box, $object_id );
|
1135 |
-
}
|
1136 |
-
|
1137 |
-
/**
|
1138 |
-
* Display a metabox form & save it on submission
|
1139 |
-
* @since 1.0.0
|
1140 |
-
* @param array $meta_box Metabox config array
|
1141 |
-
* @param int $object_id Object ID
|
1142 |
-
* @param boolean $return Whether to return or echo form
|
1143 |
-
* @return string CMB html form markup
|
1144 |
-
*/
|
1145 |
-
function cmb_metabox_form( $meta_box, $object_id, $echo = true ) {
|
1146 |
-
|
1147 |
-
$meta_box = cmb_Meta_Box::set_mb_defaults( $meta_box );
|
1148 |
-
|
1149 |
-
// Make sure form should be shown
|
1150 |
-
if ( ! apply_filters( 'cmb_show_on', true, $meta_box ) )
|
1151 |
-
return '';
|
1152 |
-
|
1153 |
-
// Make sure that our object type is explicitly set by the metabox config
|
1154 |
-
cmb_Meta_Box::set_object_type( cmb_Meta_Box::set_mb_type( $meta_box ) );
|
1155 |
-
|
1156 |
-
// Save the metabox if it's been submitted
|
1157 |
-
// check permissions
|
1158 |
-
// @todo more hardening?
|
1159 |
-
if (
|
1160 |
-
// check nonce
|
1161 |
-
isset( $_POST['submit-cmb'], $_POST['object_id'], $_POST['wp_meta_box_nonce'] )
|
1162 |
-
&& wp_verify_nonce( $_POST['wp_meta_box_nonce'], cmb_Meta_Box::nonce() )
|
1163 |
-
&& $_POST['object_id'] == $object_id
|
1164 |
-
)
|
1165 |
-
cmb_save_metabox_fields( $meta_box, $object_id );
|
1166 |
-
|
1167 |
-
// Show specific metabox form
|
1168 |
-
|
1169 |
-
// Get cmb form
|
1170 |
-
ob_start();
|
1171 |
-
cmb_print_metabox( $meta_box, $object_id );
|
1172 |
-
$form = ob_get_contents();
|
1173 |
-
ob_end_clean();
|
1174 |
-
|
1175 |
-
$form_format = apply_filters( 'cmb_frontend_form_format', '<form class="cmb-form" method="post" id="%s" enctype="multipart/form-data" encoding="multipart/form-data"><input type="hidden" name="object_id" value="%s">%s<input type="submit" name="submit-cmb" value="%s" class="button-primary"></form>', $object_id, $meta_box, $form );
|
1176 |
-
|
1177 |
-
$form = sprintf( $form_format, $meta_box['id'], $object_id, $form, __( 'Save' ) );
|
1178 |
-
|
1179 |
-
if ( $echo )
|
1180 |
-
echo $form;
|
1181 |
-
|
1182 |
-
return $form;
|
1183 |
-
}
|
1184 |
-
|
1185 |
-
// End. That's it, folks! //
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Script Name: Custom Metaboxes and Fields
|
4 |
+
Contributors: WebDevStudios (@webdevstudios / webdevstudios.com)
|
5 |
+
Justin Sternberg (@jtsternberg / dsgnwrks.pro)
|
6 |
+
Jared Atchison (@jaredatch / jaredatchison.com)
|
7 |
+
Bill Erickson (@billerickson / billerickson.net)
|
8 |
+
Andrew Norcross (@norcross / andrewnorcross.com)
|
9 |
+
Description: This will create metaboxes with custom fields that will blow your mind.
|
10 |
+
Version: 1.2.0
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Released under the GPL license
|
15 |
+
* http://www.opensource.org/licenses/gpl-license.php
|
16 |
+
*
|
17 |
+
* This is an add-on for WordPress
|
18 |
+
* http://wordpress.org/
|
19 |
+
*
|
20 |
+
* **********************************************************************
|
21 |
+
* This program is free software; you can redistribute it and/or modify
|
22 |
+
* it under the terms of the GNU General Public License as published by
|
23 |
+
* the Free Software Foundation; either version 2 of the License, or
|
24 |
+
* (at your option) any later version.
|
25 |
+
*
|
26 |
+
* This program is distributed in the hope that it will be useful,
|
27 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
28 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
29 |
+
* GNU General Public License for more details.
|
30 |
+
* **********************************************************************
|
31 |
+
*/
|
32 |
+
|
33 |
+
/************************************************************************
|
34 |
+
You should not edit the code below or things might explode!
|
35 |
+
*************************************************************************/
|
36 |
+
|
37 |
+
// Autoload helper classes
|
38 |
+
spl_autoload_register('cmb_Meta_Box::autoload_helpers');
|
39 |
+
|
40 |
+
$meta_boxes = array();
|
41 |
+
$meta_boxes = apply_filters( 'cmb_meta_boxes', $meta_boxes );
|
42 |
+
foreach ( $meta_boxes as $meta_box ) {
|
43 |
+
$my_box = new cmb_Meta_Box( $meta_box );
|
44 |
+
}
|
45 |
+
|
46 |
+
define( 'CMB_META_BOX_URL', cmb_Meta_Box::get_meta_box_url() );
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Create meta boxes
|
50 |
+
*/
|
51 |
+
class cmb_Meta_Box {
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Current version number
|
55 |
+
* @var string
|
56 |
+
* @since 1.0.0
|
57 |
+
*/
|
58 |
+
const CMB_VERSION = '1.2.0';
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Metabox Config array
|
62 |
+
* @var array
|
63 |
+
* @since 0.9.0
|
64 |
+
*/
|
65 |
+
protected $_meta_box;
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Metabox Defaults
|
69 |
+
* @var array
|
70 |
+
* @since 1.0.1
|
71 |
+
*/
|
72 |
+
protected static $mb_defaults = array(
|
73 |
+
'id' => '',
|
74 |
+
'title' => '',
|
75 |
+
'type' => '',
|
76 |
+
'pages' => array(), // Post type
|
77 |
+
'context' => 'normal',
|
78 |
+
'priority' => 'high',
|
79 |
+
'show_names' => true, // Show field names on the left
|
80 |
+
'show_on' => array( 'key' => false, 'value' => false ), // Specific post IDs or page templates to display this metabox
|
81 |
+
'cmb_styles' => true, // Include cmb bundled stylesheet
|
82 |
+
'fields' => array(),
|
83 |
+
);
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Metabox Form ID
|
87 |
+
* @var string
|
88 |
+
* @since 0.9.4
|
89 |
+
*/
|
90 |
+
protected $form_id = 'post';
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Current field config array
|
94 |
+
* @var array
|
95 |
+
* @since 1.0.0
|
96 |
+
*/
|
97 |
+
public static $field = array();
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Object ID for metabox meta retrieving/saving
|
101 |
+
* @var int
|
102 |
+
* @since 1.0.0
|
103 |
+
*/
|
104 |
+
protected static $object_id = 0;
|
105 |
+
|
106 |
+
/**
|
107 |
+
* Type of object being saved. (e.g., post, user, or comment)
|
108 |
+
* @var string
|
109 |
+
* @since 1.0.0
|
110 |
+
*/
|
111 |
+
protected static $object_type = '';
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Whether scripts/styles have been enqueued yet
|
115 |
+
* @var bool
|
116 |
+
* @since 1.0.0
|
117 |
+
*/
|
118 |
+
protected static $is_enqueued = false;
|
119 |
+
|
120 |
+
/**
|
121 |
+
* Whether CMB nonce has been added to the page. (oly add once)
|
122 |
+
* @var bool
|
123 |
+
* @since 1.2.0
|
124 |
+
*/
|
125 |
+
protected static $nonce_added = false;
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Type of object specified by the metabox Config
|
129 |
+
* @var string
|
130 |
+
* @since 1.0.0
|
131 |
+
*/
|
132 |
+
protected static $mb_object_type = 'post';
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Array of all options from manage-options metaboxes
|
136 |
+
* @var array
|
137 |
+
* @since 1.0.0
|
138 |
+
*/
|
139 |
+
protected static $options = array();
|
140 |
+
|
141 |
+
/**
|
142 |
+
* List of fields that are changed/updated on save
|
143 |
+
* @var array
|
144 |
+
* @since 1.1.0
|
145 |
+
*/
|
146 |
+
protected static $updated = array();
|
147 |
+
|
148 |
+
/**
|
149 |
+
* Get started
|
150 |
+
*/
|
151 |
+
function __construct( $meta_box ) {
|
152 |
+
|
153 |
+
$meta_box = self::set_mb_defaults( $meta_box );
|
154 |
+
|
155 |
+
$allow_frontend = apply_filters( 'cmb_allow_frontend', true, $meta_box );
|
156 |
+
|
157 |
+
if ( ! is_admin() && ! $allow_frontend )
|
158 |
+
return;
|
159 |
+
|
160 |
+
$this->_meta_box = $meta_box;
|
161 |
+
|
162 |
+
self::set_mb_type( $meta_box );
|
163 |
+
|
164 |
+
$types = wp_list_pluck( $meta_box['fields'], 'type' );
|
165 |
+
$upload = in_array( 'file', $types ) || in_array( 'file_list', $types );
|
166 |
+
|
167 |
+
global $pagenow;
|
168 |
+
|
169 |
+
$show_filters = 'cmb_Meta_Box_Show_Filters';
|
170 |
+
foreach ( get_class_methods( $show_filters ) as $filter ) {
|
171 |
+
add_filter( 'cmb_show_on', array( $show_filters, $filter ), 10, 2 );
|
172 |
+
}
|
173 |
+
|
174 |
+
// register our scripts and styles for cmb
|
175 |
+
add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts' ), 8 );
|
176 |
+
|
177 |
+
if ( self::get_object_type() == 'post' ) {
|
178 |
+
add_action( 'admin_menu', array( $this, 'add_metaboxes' ) );
|
179 |
+
add_action( 'add_attachment', array( $this, 'save_post' ) );
|
180 |
+
add_action( 'edit_attachment', array( $this, 'save_post' ) );
|
181 |
+
add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
|
182 |
+
add_action( 'admin_enqueue_scripts', array( $this, 'do_scripts' ) );
|
183 |
+
|
184 |
+
if ( $upload && in_array( $pagenow, array( 'page.php', 'page-new.php', 'post.php', 'post-new.php' ) ) ) {
|
185 |
+
add_action( 'admin_head', array( $this, 'add_post_enctype' ) );
|
186 |
+
}
|
187 |
+
|
188 |
+
}
|
189 |
+
if ( self::get_object_type() == 'user' ) {
|
190 |
+
|
191 |
+
$priority = 10;
|
192 |
+
if ( isset( $meta_box['priority'] ) ) {
|
193 |
+
if ( is_numeric( $meta_box['priority'] ) )
|
194 |
+
$priority = $meta_box['priority'];
|
195 |
+
elseif ( $meta_box['priority'] == 'high' )
|
196 |
+
$priority = 5;
|
197 |
+
elseif ( $meta_box['priority'] == 'low' )
|
198 |
+
$priority = 20;
|
199 |
+
}
|
200 |
+
add_action( 'show_user_profile', array( $this, 'user_metabox' ), $priority );
|
201 |
+
add_action( 'edit_user_profile', array( $this, 'user_metabox' ), $priority );
|
202 |
+
|
203 |
+
add_action( 'personal_options_update', array( $this, 'save_user' ) );
|
204 |
+
add_action( 'edit_user_profile_update', array( $this, 'save_user' ) );
|
205 |
+
if ( $upload && in_array( $pagenow, array( 'profile.php', 'user-edit.php' ) ) ) {
|
206 |
+
$this->form_id = 'your-profile';
|
207 |
+
add_action( 'admin_head', array( $this, 'add_post_enctype' ) );
|
208 |
+
}
|
209 |
+
}
|
210 |
+
|
211 |
+
}
|
212 |
+
|
213 |
+
/**
|
214 |
+
* Autoloads files with classes when needed
|
215 |
+
* @since 1.0.0
|
216 |
+
* @param string $class_name Name of the class being requested
|
217 |
+
*/
|
218 |
+
public static function autoload_helpers( $class_name ) {
|
219 |
+
if ( class_exists( $class_name, false ) )
|
220 |
+
return;
|
221 |
+
|
222 |
+
// for PHP versions < 5.3
|
223 |
+
$dir = dirname( __FILE__ );
|
224 |
+
|
225 |
+
$file = "$dir/helpers/$class_name.php";
|
226 |
+
if ( file_exists( $file ) )
|
227 |
+
@include( $file );
|
228 |
+
}
|
229 |
+
|
230 |
+
/**
|
231 |
+
* Registers scripts and styles for CMB
|
232 |
+
* @since 1.0.0
|
233 |
+
*/
|
234 |
+
public function register_scripts() {
|
235 |
+
|
236 |
+
// Should only be run once
|
237 |
+
if ( self::$is_enqueued )
|
238 |
+
return;
|
239 |
+
|
240 |
+
global $wp_version;
|
241 |
+
// Only use minified files if SCRIPT_DEBUG is off
|
242 |
+
$min = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
|
243 |
+
|
244 |
+
// scripts required for cmb
|
245 |
+
$scripts = array( 'jquery', 'jquery-ui-core', 'cmb-datepicker', /*'media-upload', */'cmb-timepicker' );
|
246 |
+
// styles required for cmb
|
247 |
+
$styles = array();
|
248 |
+
|
249 |
+
// if we're 3.5 or later, user wp-color-picker
|
250 |
+
if ( 3.5 <= $wp_version ) {
|
251 |
+
$scripts[] = 'wp-color-picker';
|
252 |
+
$styles[] = 'wp-color-picker';
|
253 |
+
if ( ! is_admin() ) {
|
254 |
+
// we need to register colorpicker on the front-end
|
255 |
+
wp_register_script( 'iris', admin_url( 'js/iris.min.js' ), array( 'jquery-ui-draggable', 'jquery-ui-slider', 'jquery-touch-punch' ), self::CMB_VERSION );
|
256 |
+
wp_register_script( 'wp-color-picker', admin_url( 'js/color-picker.min.js' ), array( 'iris' ), self::CMB_VERSION );
|
257 |
+
wp_localize_script( 'wp-color-picker', 'wpColorPickerL10n', array(
|
258 |
+
'clear' => __( 'Clear' ),
|
259 |
+
'defaultString' => __( 'Default' ),
|
260 |
+
'pick' => __( 'Select Color' ),
|
261 |
+
'current' => __( 'Current Color' ),
|
262 |
+
) );
|
263 |
+
}
|
264 |
+
} else {
|
265 |
+
// otherwise use the older 'farbtastic'
|
266 |
+
$scripts[] = 'farbtastic';
|
267 |
+
$styles[] = 'farbtastic';
|
268 |
+
}
|
269 |
+
wp_register_script( 'cmb-datepicker', CMB_META_BOX_URL . 'js/jquery.datePicker.min.js' );
|
270 |
+
wp_register_script( 'cmb-timepicker', CMB_META_BOX_URL . 'js/jquery.timePicker.min.js' );
|
271 |
+
wp_register_script( 'cmb-scripts', CMB_META_BOX_URL .'js/cmb'. $min .'.js', $scripts, self::CMB_VERSION );
|
272 |
+
|
273 |
+
wp_enqueue_media();
|
274 |
+
|
275 |
+
wp_localize_script( 'cmb-scripts', 'cmb_l10', apply_filters( 'cmb_localized_data', array(
|
276 |
+
'ajax_nonce' => wp_create_nonce( 'ajax_nonce' ),
|
277 |
+
'script_debug' => defined('SCRIPT_DEBUG') && SCRIPT_DEBUG,
|
278 |
+
'new_admin_style' => version_compare( $wp_version, '3.7', '>' ),
|
279 |
+
'object_type' => self::get_object_type(),
|
280 |
+
'upload_file' => 'Use this file',
|
281 |
+
'remove_image' => 'Remove Image',
|
282 |
+
'remove_file' => 'Remove',
|
283 |
+
'file' => 'File:',
|
284 |
+
'download' => 'Download',
|
285 |
+
'ajaxurl' => admin_url( '/admin-ajax.php' ),
|
286 |
+
'up_arrow' => '[ ↑ ] ',
|
287 |
+
'down_arrow' => ' [ ↓ ]',
|
288 |
+
'check_toggle' => __( 'Select / Deselect All', 'cmb' ),
|
289 |
+
) ) );
|
290 |
+
|
291 |
+
wp_register_style( 'cmb-styles', CMB_META_BOX_URL . 'style'. $min .'.css', $styles );
|
292 |
+
|
293 |
+
// Ok, we've enqueued our scripts/styles
|
294 |
+
self::$is_enqueued = true;
|
295 |
+
}
|
296 |
+
|
297 |
+
/**
|
298 |
+
* Enqueues scripts and styles for CMB
|
299 |
+
* @since 1.0.0
|
300 |
+
*/
|
301 |
+
public function do_scripts( $hook ) {
|
302 |
+
// only enqueue our scripts/styles on the proper pages
|
303 |
+
if ( $hook == 'post.php' || $hook == 'post-new.php' || $hook == 'page-new.php' || $hook == 'page.php' ) {
|
304 |
+
wp_enqueue_script( 'cmb-scripts' );
|
305 |
+
|
306 |
+
// default is to show cmb styles on post pages
|
307 |
+
if ( $this->_meta_box['cmb_styles'] )
|
308 |
+
wp_enqueue_style( 'cmb-styles' );
|
309 |
+
}
|
310 |
+
}
|
311 |
+
|
312 |
+
/**
|
313 |
+
* Add encoding attribute
|
314 |
+
*/
|
315 |
+
public function add_post_enctype() {
|
316 |
+
echo '
|
317 |
+
<script type="text/javascript">
|
318 |
+
jQuery(document).ready(function(){
|
319 |
+
jQuery("#'. $this->form_id .'").attr("enctype", "multipart/form-data");
|
320 |
+
jQuery("#'. $this->form_id .'").attr("encoding", "multipart/form-data");
|
321 |
+
});
|
322 |
+
</script>';
|
323 |
+
}
|
324 |
+
|
325 |
+
/**
|
326 |
+
* Add metaboxes (to 'post' object type)
|
327 |
+
*/
|
328 |
+
public function add_metaboxes() {
|
329 |
+
|
330 |
+
foreach ( $this->_meta_box['pages'] as $page ) {
|
331 |
+
if ( apply_filters( 'cmb_show_on', true, $this->_meta_box ) )
|
332 |
+
add_meta_box( $this->_meta_box['id'], $this->_meta_box['title'], array( $this, 'post_metabox' ), $page, $this->_meta_box['context'], $this->_meta_box['priority']) ;
|
333 |
+
}
|
334 |
+
}
|
335 |
+
|
336 |
+
/**
|
337 |
+
* Display metaboxes for a post object
|
338 |
+
* @since 1.0.0
|
339 |
+
*/
|
340 |
+
public function post_metabox() {
|
341 |
+
if ( ! $this->_meta_box )
|
342 |
+
return;
|
343 |
+
|
344 |
+
self::show_form( $this->_meta_box, get_the_ID(), 'post' );
|
345 |
+
|
346 |
+
}
|
347 |
+
|
348 |
+
/**
|
349 |
+
* Display metaboxes for a user object
|
350 |
+
* @since 1.0.0
|
351 |
+
*/
|
352 |
+
public function user_metabox() {
|
353 |
+
if ( ! $this->_meta_box )
|
354 |
+
return;
|
355 |
+
|
356 |
+
if ( 'user' != self::set_mb_type( $this->_meta_box ) )
|
357 |
+
return;
|
358 |
+
|
359 |
+
if ( ! apply_filters( 'cmb_show_on', true, $this->_meta_box ) )
|
360 |
+
return;
|
361 |
+
|
362 |
+
wp_enqueue_script( 'cmb-scripts' );
|
363 |
+
|
364 |
+
// default is to NOT show cmb styles on user profile page
|
365 |
+
if ( $this->_meta_box['cmb_styles'] != false )
|
366 |
+
wp_enqueue_style( 'cmb-styles' );
|
367 |
+
|
368 |
+
self::show_form( $this->_meta_box );
|
369 |
+
|
370 |
+
}
|
371 |
+
|
372 |
+
/**
|
373 |
+
* Loops through and displays fields
|
374 |
+
* @since 1.0.0
|
375 |
+
* @param array $meta_box Metabox config array
|
376 |
+
* @param int $object_id Object ID
|
377 |
+
* @param string $object_type Type of object being saved. (e.g., post, user, or comment)
|
378 |
+
*/
|
379 |
+
public static function show_form( $meta_box, $object_id = 0, $object_type = '' ) {
|
380 |
+
$meta_box = self::set_mb_defaults( $meta_box );
|
381 |
+
// Set/get type
|
382 |
+
$object_type = self::set_object_type( $object_type ? $object_type : self::set_mb_type( $meta_box ) );
|
383 |
+
// Set/get ID
|
384 |
+
$object_id = self::set_object_id( $object_id ? $object_id : self::get_object_id() );
|
385 |
+
|
386 |
+
// Add nonce only once per page.
|
387 |
+
if ( ! self::$nonce_added ) {
|
388 |
+
wp_nonce_field( self::nonce(), 'wp_meta_box_nonce', false, true );
|
389 |
+
self::$nonce_added = true;
|
390 |
+
}
|
391 |
+
|
392 |
+
// Use nonce for verification
|
393 |
+
echo "\n<!-- Begin CMB Fields -->\n";
|
394 |
+
do_action( 'cmb_before_table', $meta_box, $object_id, $object_type );
|
395 |
+
echo '<table class="form-table cmb_metabox">';
|
396 |
+
|
397 |
+
foreach ( $meta_box['fields'] as $field_args ) {
|
398 |
+
|
399 |
+
$field_args['context'] = $meta_box['context'];
|
400 |
+
|
401 |
+
if ( 'group' == $field_args['type'] ) {
|
402 |
+
|
403 |
+
if ( ! isset( $field_args['show_names'] ) ) {
|
404 |
+
$field_args['show_names'] = $meta_box['show_names'];
|
405 |
+
}
|
406 |
+
self::render_group( $field_args );
|
407 |
+
} else {
|
408 |
+
|
409 |
+
$field_args['show_names'] = $meta_box['show_names'];
|
410 |
+
// Render default fields
|
411 |
+
$field = new cmb_Meta_Box_field( $field_args );
|
412 |
+
$field->render_field();
|
413 |
+
}
|
414 |
+
}
|
415 |
+
echo '</table>';
|
416 |
+
do_action( 'cmb_after_table', $meta_box, $object_id, $object_type );
|
417 |
+
echo "\n<!-- End CMB Fields -->\n";
|
418 |
+
|
419 |
+
}
|
420 |
+
|
421 |
+
/**
|
422 |
+
* Render a repeatable group
|
423 |
+
*/
|
424 |
+
public static function render_group( $args ) {
|
425 |
+
if ( ! isset( $args['id'], $args['fields'] ) || ! is_array( $args['fields'] ) )
|
426 |
+
return;
|
427 |
+
|
428 |
+
$args['count'] = 0;
|
429 |
+
$field_group = new cmb_Meta_Box_field( $args );
|
430 |
+
$desc = $field_group->args( 'description' );
|
431 |
+
$label = $field_group->args( 'name' );
|
432 |
+
$sortable = $field_group->options( 'sortable' ) ? ' sortable' : '';
|
433 |
+
$group_val = (array) $field_group->value();
|
434 |
+
$nrows = count( $group_val );
|
435 |
+
$remove_disabled = $nrows <= 1 ? 'disabled="disabled" ' : '';
|
436 |
+
|
437 |
+
echo '<tr><td colspan="2"><table id="', $field_group->id(), '_repeat" class="repeatable-group'. $sortable .'" style="width:100%;">';
|
438 |
+
if ( $desc || $label ) {
|
439 |
+
echo '<tr><th>';
|
440 |
+
if ( $label )
|
441 |
+
echo '<h2 class="cmb-group-name">'. $label .'</h2>';
|
442 |
+
if ( $desc )
|
443 |
+
echo '<p class="cmb_metabox_description">'. $desc .'</p>';
|
444 |
+
echo '</th></tr>';
|
445 |
+
}
|
446 |
+
|
447 |
+
if ( ! empty( $group_val ) ) {
|
448 |
+
|
449 |
+
foreach ( $group_val as $iterator => $field_id ) {
|
450 |
+
self::render_group_row( $field_group, $remove_disabled );
|
451 |
+
}
|
452 |
+
} else {
|
453 |
+
self::render_group_row( $field_group, $remove_disabled );
|
454 |
+
}
|
455 |
+
|
456 |
+
echo '<tr><td><p class="add-row"><button data-selector="', $field_group->id() ,'_repeat" data-grouptitle="', $field_group->options( 'group_title' ) ,'" class="add-group-row button">'. $field_group->options( 'add_button' ) .'</button></p></td></tr>';
|
457 |
+
|
458 |
+
echo '</table></td></tr>';
|
459 |
+
|
460 |
+
}
|
461 |
+
|
462 |
+
public static function render_group_row( $field_group, $remove_disabled ) {
|
463 |
+
|
464 |
+
echo '
|
465 |
+
<tr class="repeatable-grouping" data-iterator="'. $field_group->count() .'">
|
466 |
+
<td>
|
467 |
+
<table class="cmb-nested-table" style="width: 100%;">';
|
468 |
+
if ( $field_group->options( 'group_title' ) ) {
|
469 |
+
echo '
|
470 |
+
<tr class="cmb-group-title">
|
471 |
+
<th colspan="2">
|
472 |
+
', sprintf( '<h4>%1$s</h4>', $field_group->replace_hash( $field_group->options( 'group_title' ) ) ), '
|
473 |
+
<th>
|
474 |
+
</tr>
|
475 |
+
';
|
476 |
+
}
|
477 |
+
// Render repeatable group fields
|
478 |
+
foreach ( array_values( $field_group->args( 'fields' ) ) as $field_args ) {
|
479 |
+
$field_args['show_names'] = $field_group->args( 'show_names' );
|
480 |
+
$field_args['context'] = $field_group->args( 'context' );
|
481 |
+
$field = new cmb_Meta_Box_field( $field_args, $field_group );
|
482 |
+
$field->render_field();
|
483 |
+
}
|
484 |
+
echo '
|
485 |
+
<tr>
|
486 |
+
<td class="remove-row" colspan="2">
|
487 |
+
<button '. $remove_disabled .'data-selector="'. $field_group->id() .'_repeat" class="button remove-group-row alignright">'. $field_group->options( 'remove_button' ) .'</button>
|
488 |
+
</td>
|
489 |
+
</tr>
|
490 |
+
</table>
|
491 |
+
</td>
|
492 |
+
</tr>
|
493 |
+
';
|
494 |
+
|
495 |
+
$field_group->args['count']++;
|
496 |
+
}
|
497 |
+
|
498 |
+
/**
|
499 |
+
* Save data from metabox
|
500 |
+
*/
|
501 |
+
public function save_post( $post_id, $post = false ) {
|
502 |
+
|
503 |
+
$post_type = $post ? $post->post_type : get_post_type( $post_id );
|
504 |
+
|
505 |
+
// check permissions
|
506 |
+
if (
|
507 |
+
// check nonce
|
508 |
+
! isset( $_POST['wp_meta_box_nonce'] )
|
509 |
+
|| ! wp_verify_nonce( $_POST['wp_meta_box_nonce'], self::nonce() )
|
510 |
+
// check if autosave
|
511 |
+
|| defined('DOING_AUTOSAVE' ) && DOING_AUTOSAVE
|
512 |
+
// check user editing permissions
|
513 |
+
|| ( 'page' == $_POST['post_type'] && ! current_user_can( 'edit_page', $post_id ) )
|
514 |
+
|| ! current_user_can( 'edit_post', $post_id )
|
515 |
+
// get the metabox post_types & compare it to this post_type
|
516 |
+
|| ! in_array( $post_type, $this->_meta_box['pages'] )
|
517 |
+
)
|
518 |
+
return $post_id;
|
519 |
+
|
520 |
+
self::save_fields( $this->_meta_box, $post_id, 'post' );
|
521 |
+
}
|
522 |
+
|
523 |
+
/**
|
524 |
+
* Save data from metabox
|
525 |
+
*/
|
526 |
+
public function save_user( $user_id ) {
|
527 |
+
|
528 |
+
// check permissions
|
529 |
+
// @todo more hardening?
|
530 |
+
if (
|
531 |
+
// check nonce
|
532 |
+
! isset( $_POST['wp_meta_box_nonce'] )
|
533 |
+
|| ! wp_verify_nonce( $_POST['wp_meta_box_nonce'], self::nonce() )
|
534 |
+
)
|
535 |
+
return $user_id;
|
536 |
+
|
537 |
+
self::save_fields( $this->_meta_box, $user_id, 'user' );
|
538 |
+
}
|
539 |
+
|
540 |
+
/**
|
541 |
+
* Loops through and saves field data
|
542 |
+
* @since 1.0.0
|
543 |
+
* @param array $meta_box Metabox config array
|
544 |
+
* @param int $object_id Object ID
|
545 |
+
* @param string $object_type Type of object being saved. (e.g., post, user, or comment)
|
546 |
+
*/
|
547 |
+
public static function save_fields( $meta_box, $object_id, $object_type = '' ) {
|
548 |
+
$meta_box = self::set_mb_defaults( $meta_box );
|
549 |
+
|
550 |
+
$meta_box['show_on'] = empty( $meta_box['show_on'] ) ? array( 'key' => false, 'value' => false ) : $meta_box['show_on'];
|
551 |
+
|
552 |
+
self::set_object_id( $object_id );
|
553 |
+
// Set/get type
|
554 |
+
$object_type = self::set_object_type( $object_type ? $object_type : self::set_mb_type( $meta_box ) );
|
555 |
+
|
556 |
+
if ( ! apply_filters( 'cmb_show_on', true, $meta_box ) )
|
557 |
+
return;
|
558 |
+
|
559 |
+
// save field ids of those that are updated
|
560 |
+
self::$updated = array();
|
561 |
+
|
562 |
+
foreach ( $meta_box['fields'] as $field_args ) {
|
563 |
+
|
564 |
+
if ( 'group' == $field_args['type'] ) {
|
565 |
+
self::save_group( $field_args );
|
566 |
+
} else {
|
567 |
+
// Save default fields
|
568 |
+
$field = new cmb_Meta_Box_field( $field_args );
|
569 |
+
self::save_field( self::sanitize_field( $field ), $field );
|
570 |
+
}
|
571 |
+
|
572 |
+
}
|
573 |
+
|
574 |
+
// If options page, save the updated options
|
575 |
+
if ( $object_type == 'options-page' )
|
576 |
+
self::save_option( $object_id );
|
577 |
+
|
578 |
+
do_action( "cmb_save_{$object_type}_fields", $object_id, $meta_box['id'], self::$updated, $meta_box );
|
579 |
+
|
580 |
+
}
|
581 |
+
|
582 |
+
/**
|
583 |
+
* Save a repeatable group
|
584 |
+
*/
|
585 |
+
public static function save_group( $args ) {
|
586 |
+
if ( ! isset( $args['id'], $args['fields'], $_POST[ $args['id'] ] ) || ! is_array( $args['fields'] ) )
|
587 |
+
return;
|
588 |
+
|
589 |
+
$field_group = new cmb_Meta_Box_field( $args );
|
590 |
+
$base_id = $field_group->id();
|
591 |
+
$old = $field_group->get_data();
|
592 |
+
$group_vals = $_POST[ $base_id ];
|
593 |
+
$saved = array();
|
594 |
+
$is_updated = false;
|
595 |
+
$field_group->index = 0;
|
596 |
+
|
597 |
+
// $group_vals[0]['color'] = '333';
|
598 |
+
foreach ( array_values( $field_group->fields() ) as $field_args ) {
|
599 |
+
$field = new cmb_Meta_Box_field( $field_args, $field_group );
|
600 |
+
$sub_id = $field->id( true );
|
601 |
+
|
602 |
+
foreach ( (array) $group_vals as $field_group->index => $post_vals ) {
|
603 |
+
|
604 |
+
// Get value
|
605 |
+
$new_val = isset( $group_vals[ $field_group->index ][ $sub_id ] )
|
606 |
+
? $group_vals[ $field_group->index ][ $sub_id ]
|
607 |
+
: false;
|
608 |
+
|
609 |
+
// Sanitize
|
610 |
+
$new_val = self::sanitize_field( $field, $new_val, $field_group->index );
|
611 |
+
|
612 |
+
if ( 'file' == $field->type() && is_array( $new_val ) ) {
|
613 |
+
// Add image ID to the array stack
|
614 |
+
$saved[ $field_group->index ][ $new_val['field_id'] ] = $new_val['attach_id'];
|
615 |
+
// Reset var to url string
|
616 |
+
$new_val = $new_val['url'];
|
617 |
+
}
|
618 |
+
|
619 |
+
// Get old value
|
620 |
+
$old_val = is_array( $old ) && isset( $old[ $field_group->index ][ $sub_id ] )
|
621 |
+
? $old[ $field_group->index ][ $sub_id ]
|
622 |
+
: false;
|
623 |
+
|
624 |
+
$is_updated = ( ! empty( $new_val ) && $new_val != $old_val );
|
625 |
+
$is_removed = ( empty( $new_val ) && ! empty( $old_val ) );
|
626 |
+
// Compare values and add to `$updated` array
|
627 |
+
if ( $is_updated || $is_removed )
|
628 |
+
self::$updated[] = $base_id .'::'. $field_group->index .'::'. $sub_id;
|
629 |
+
|
630 |
+
// Add to `$saved` array
|
631 |
+
$saved[ $field_group->index ][ $sub_id ] = $new_val;
|
632 |
+
|
633 |
+
}
|
634 |
+
$saved[ $field_group->index ] = array_filter( $saved[ $field_group->index ] );
|
635 |
+
}
|
636 |
+
$saved = array_filter( $saved );
|
637 |
+
|
638 |
+
$field_group->update_data( $saved, true );
|
639 |
+
}
|
640 |
+
|
641 |
+
public static function sanitize_field( $field, $new_value = null ) {
|
642 |
+
|
643 |
+
$new_value = null !== $new_value
|
644 |
+
? $new_value
|
645 |
+
: ( isset( $_POST[ $field->id( true ) ] ) ? $_POST[ $field->id( true ) ] : null );
|
646 |
+
|
647 |
+
if ( $field->args( 'repeatable' ) && is_array( $new_value ) ) {
|
648 |
+
// Remove empties
|
649 |
+
$new_value = array_filter( $new_value );
|
650 |
+
}
|
651 |
+
|
652 |
+
// Check if this metabox field has a registered validation callback, or perform default sanitization
|
653 |
+
return $field->sanitization_cb( $new_value );
|
654 |
+
}
|
655 |
+
|
656 |
+
public static function save_field( $new_value, $field ) {
|
657 |
+
$name = $field->id();
|
658 |
+
$old = $field->get_data();
|
659 |
+
|
660 |
+
// if ( $field->args( 'multiple' ) && ! $field->args( 'repeatable' ) && ! $field->group ) {
|
661 |
+
// $field->remove_data();
|
662 |
+
// if ( ! empty( $new_value ) ) {
|
663 |
+
// foreach ( $new_value as $add_new ) {
|
664 |
+
// self::$updated[] = $name;
|
665 |
+
// $field->update_data( $add_new, $name, false );
|
666 |
+
// }
|
667 |
+
// }
|
668 |
+
// } else
|
669 |
+
if ( ! empty( $new_value ) && $new_value != $old ) {
|
670 |
+
self::$updated[] = $name;
|
671 |
+
return $field->update_data( $new_value );
|
672 |
+
} elseif ( empty( $new_value ) ) {
|
673 |
+
if ( ! empty( $old ) )
|
674 |
+
self::$updated[] = $name;
|
675 |
+
return $field->remove_data();
|
676 |
+
}
|
677 |
+
}
|
678 |
+
|
679 |
+
/**
|
680 |
+
* Get object id from global space if no id is provided
|
681 |
+
* @since 1.0.0
|
682 |
+
* @param integer $object_id Object ID
|
683 |
+
* @return integer $object_id Object ID
|
684 |
+
*/
|
685 |
+
public static function get_object_id( $object_id = 0 ) {
|
686 |
+
|
687 |
+
if ( $object_id )
|
688 |
+
return $object_id;
|
689 |
+
|
690 |
+
if ( self::$object_id )
|
691 |
+
return self::$object_id;
|
692 |
+
|
693 |
+
// Try to get our object ID from the global space
|
694 |
+
switch ( self::get_object_type() ) {
|
695 |
+
case 'user':
|
696 |
+
$object_id = isset( $GLOBALS['user_ID'] ) ? $GLOBALS['user_ID'] : $object_id;
|
697 |
+
$object_id = isset( $_REQUEST['user_id'] ) ? $_REQUEST['user_id'] : $object_id;
|
698 |
+
break;
|
699 |
+
|
700 |
+
default:
|
701 |
+
$object_id = isset( $GLOBALS['post']->ID ) ? $GLOBALS['post']->ID : $object_id;
|
702 |
+
$object_id = isset( $_REQUEST['post'] ) ? $_REQUEST['post'] : $object_id;
|
703 |
+
break;
|
704 |
+
}
|
705 |
+
|
706 |
+
// reset to id or 0
|
707 |
+
self::set_object_id( $object_id ? $object_id : 0 );
|
708 |
+
|
709 |
+
return self::$object_id;
|
710 |
+
}
|
711 |
+
|
712 |
+
/**
|
713 |
+
* Explicitly Set object id
|
714 |
+
* @since 1.0.0
|
715 |
+
* @param integer $object_id Object ID
|
716 |
+
* @return integer $object_id Object ID
|
717 |
+
*/
|
718 |
+
public static function set_object_id( $object_id ) {
|
719 |
+
return self::$object_id = $object_id;
|
720 |
+
}
|
721 |
+
|
722 |
+
/**
|
723 |
+
* Sets the $object_type based on metabox settings
|
724 |
+
* @since 1.0.0
|
725 |
+
* @param array|string $meta_box Metabox config array or explicit setting
|
726 |
+
* @return string Object type
|
727 |
+
*/
|
728 |
+
public static function set_mb_type( $meta_box ) {
|
729 |
+
|
730 |
+
if ( is_string( $meta_box ) ) {
|
731 |
+
self::$mb_object_type = $meta_box;
|
732 |
+
return self::get_mb_type();
|
733 |
+
}
|
734 |
+
|
735 |
+
if ( ! isset( $meta_box['pages'] ) )
|
736 |
+
return self::get_mb_type();
|
737 |
+
|
738 |
+
$type = false;
|
739 |
+
// check if 'pages' is a string
|
740 |
+
if ( self::is_options_page_mb( $meta_box ) )
|
741 |
+
$type = 'options-page';
|
742 |
+
// check if 'pages' is a string
|
743 |
+
elseif ( is_string( $meta_box['pages'] ) )
|
744 |
+
$type = $meta_box['pages'];
|
745 |
+
// if it's an array of one, extract it
|
746 |
+
elseif ( is_array( $meta_box['pages'] ) && count( $meta_box['pages'] === 1 ) )
|
747 |
+
$type = is_string( end( $meta_box['pages'] ) ) ? end( $meta_box['pages'] ) : false;
|
748 |
+
|
749 |
+
if ( !$type )
|
750 |
+
return self::get_mb_type();
|
751 |
+
|
752 |
+
// Get our object type
|
753 |
+
if ( 'user' == $type )
|
754 |
+
self::$mb_object_type = 'user';
|
755 |
+
elseif ( 'comment' == $type )
|
756 |
+
self::$mb_object_type = 'comment';
|
757 |
+
elseif ( 'options-page' == $type )
|
758 |
+
self::$mb_object_type = 'options-page';
|
759 |
+
else
|
760 |
+
self::$mb_object_type = 'post';
|
761 |
+
|
762 |
+
return self::get_mb_type();
|
763 |
+
}
|
764 |
+
|
765 |
+
/**
|
766 |
+
* Determines if metabox is for an options page
|
767 |
+
* @since 1.0.1
|
768 |
+
* @param array $meta_box Metabox config array
|
769 |
+
* @return boolean True/False
|
770 |
+
*/
|
771 |
+
public static function is_options_page_mb( $meta_box ) {
|
772 |
+
return ( isset( $meta_box['show_on']['key'] ) && 'options-page' === $meta_box['show_on']['key'] );
|
773 |
+
}
|
774 |
+
|
775 |
+
/**
|
776 |
+
* Returns the object type
|
777 |
+
* @since 1.0.0
|
778 |
+
* @return string Object type
|
779 |
+
*/
|
780 |
+
public static function get_object_type() {
|
781 |
+
if ( self::$object_type )
|
782 |
+
return self::$object_type;
|
783 |
+
|
784 |
+
global $pagenow;
|
785 |
+
|
786 |
+
if (
|
787 |
+
$pagenow == 'user-edit.php'
|
788 |
+
|| $pagenow == 'profile.php'
|
789 |
+
)
|
790 |
+
self::set_object_type( 'user' );
|
791 |
+
|
792 |
+
elseif (
|
793 |
+
$pagenow == 'edit-comments.php'
|
794 |
+
|| $pagenow == 'comment.php'
|
795 |
+
)
|
796 |
+
self::set_object_type( 'comment' );
|
797 |
+
else
|
798 |
+
self::set_object_type( 'post' );
|
799 |
+
|
800 |
+
return self::$object_type;
|
801 |
+
}
|
802 |
+
|
803 |
+
/**
|
804 |
+
* Sets the object type
|
805 |
+
* @since 1.0.0
|
806 |
+
* @return string Object type
|
807 |
+
*/
|
808 |
+
public static function set_object_type( $object_type ) {
|
809 |
+
return self::$object_type = $object_type;
|
810 |
+
}
|
811 |
+
|
812 |
+
/**
|
813 |
+
* Returns the object type
|
814 |
+
* @since 1.0.0
|
815 |
+
* @return string Object type
|
816 |
+
*/
|
817 |
+
public static function get_mb_type() {
|
818 |
+
return self::$mb_object_type;
|
819 |
+
}
|
820 |
+
|
821 |
+
/**
|
822 |
+
* Returns the nonce value for wp_meta_box_nonce
|
823 |
+
* @since 1.0.0
|
824 |
+
* @return string Nonce value
|
825 |
+
*/
|
826 |
+
public static function nonce() {
|
827 |
+
return basename( __FILE__ );
|
828 |
+
}
|
829 |
+
|
830 |
+
/**
|
831 |
+
* Defines the url which is used to load local resources.
|
832 |
+
* This may need to be filtered for local Window installations.
|
833 |
+
* If resources do not load, please check the wiki for details.
|
834 |
+
* @since 1.0.1
|
835 |
+
* @return string URL to CMB resources
|
836 |
+
*/
|
837 |
+
public static function get_meta_box_url() {
|
838 |
+
|
839 |
+
if ( strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN' ) {
|
840 |
+
// Windows
|
841 |
+
$content_dir = str_replace( '/', DIRECTORY_SEPARATOR, WP_CONTENT_DIR );
|
842 |
+
$content_url = str_replace( $content_dir, WP_CONTENT_URL, dirname(__FILE__) );
|
843 |
+
$cmb_url = str_replace( DIRECTORY_SEPARATOR, '/', $content_url );
|
844 |
+
|
845 |
+
} else {
|
846 |
+
$cmb_url = str_replace(
|
847 |
+
array(WP_CONTENT_DIR, WP_PLUGIN_DIR),
|
848 |
+
array(WP_CONTENT_URL, WP_PLUGIN_URL),
|
849 |
+
dirname( __FILE__ )
|
850 |
+
);
|
851 |
+
}
|
852 |
+
|
853 |
+
return trailingslashit( apply_filters('cmb_meta_box_url', $cmb_url ) );
|
854 |
+
}
|
855 |
+
|
856 |
+
/**
|
857 |
+
* Fills in empty metabox parameters with defaults
|
858 |
+
* @since 1.0.1
|
859 |
+
* @param array $meta_box Metabox config array
|
860 |
+
* @return array Modified Metabox config array
|
861 |
+
*/
|
862 |
+
public static function set_mb_defaults( $meta_box ) {
|
863 |
+
return wp_parse_args( $meta_box, self::$mb_defaults );
|
864 |
+
}
|
865 |
+
|
866 |
+
/**
|
867 |
+
* Removes an option from an option array
|
868 |
+
* @since 1.0.1
|
869 |
+
* @param string $option_key Option key
|
870 |
+
* @param string $field_id Option array field key
|
871 |
+
* @return array Modified options
|
872 |
+
*/
|
873 |
+
public static function remove_option( $option_key, $field_id ) {
|
874 |
+
|
875 |
+
self::$options[ $option_key ] = ! isset( self::$options[ $option_key ] ) || empty( self::$options[ $option_key ] ) ? self::_get_option( $option_key ) : self::$options[ $option_key ];
|
876 |
+
|
877 |
+
if ( isset( self::$options[ $option_key ][ $field_id ] ) )
|
878 |
+
unset( self::$options[ $option_key ][ $field_id ] );
|
879 |
+
|
880 |
+
return self::$options[ $option_key ];
|
881 |
+
}
|
882 |
+
|
883 |
+
/**
|
884 |
+
* Retrieves an option from an option array
|
885 |
+
* @since 1.0.1
|
886 |
+
* @param string $option_key Option key
|
887 |
+
* @param string $field_id Option array field key
|
888 |
+
* @return array Options array or specific field
|
889 |
+
*/
|
890 |
+
public static function get_option( $option_key, $field_id = '' ) {
|
891 |
+
|
892 |
+
self::$options[ $option_key ] = ! isset( self::$options[ $option_key ] ) || empty( self::$options[ $option_key ] ) ? self::_get_option( $option_key ) : self::$options[ $option_key ];
|
893 |
+
|
894 |
+
if ( $field_id ) {
|
895 |
+
return isset( self::$options[ $option_key ][ $field_id ] ) ? self::$options[ $option_key ][ $field_id ] : false;
|
896 |
+
}
|
897 |
+
|
898 |
+
return self::$options[ $option_key ];
|
899 |
+
}
|
900 |
+
|
901 |
+
/**
|
902 |
+
* Updates Option data
|
903 |
+
* @since 1.0.1
|
904 |
+
* @param string $option_key Option key
|
905 |
+
* @param string $field_id Option array field key
|
906 |
+
* @param mixed $value Value to update data with
|
907 |
+
* @param bool $single Whether data should be an array
|
908 |
+
* @return array Modified options
|
909 |
+
*/
|
910 |
+
public static function update_option( $option_key, $field_id, $value, $single = true ) {
|
911 |
+
|
912 |
+
if ( ! $single ) {
|
913 |
+
// If multiple, add to array
|
914 |
+
self::$options[ $option_key ][ $field_id ][] = $value;
|
915 |
+
} else {
|
916 |
+
self::$options[ $option_key ][ $field_id ] = $value;
|
917 |
+
}
|
918 |
+
|
919 |
+
return self::$options[ $option_key ];
|
920 |
+
}
|
921 |
+
|
922 |
+
/**
|
923 |
+
* Retrieve option value based on name of option.
|
924 |
+
* @uses apply_filters() Calls 'cmb_override_option_get_$option_key' hook to allow
|
925 |
+
* overwriting the option value to be retrieved.
|
926 |
+
*
|
927 |
+
* @since 1.0.1
|
928 |
+
* @param string $option Name of option to retrieve. Expected to not be SQL-escaped.
|
929 |
+
* @param mixed $default Optional. Default value to return if the option does not exist.
|
930 |
+
* @return mixed Value set for the option.
|
931 |
+
*/
|
932 |
+
public static function _get_option( $option_key, $default = false ) {
|
933 |
+
|
934 |
+
$test_get = apply_filters( "cmb_override_option_get_$option_key", 'cmb_no_override_option_get', $default );
|
935 |
+
|
936 |
+
if ( $test_get !== 'cmb_no_override_option_get' )
|
937 |
+
return $test_get;
|
938 |
+
|
939 |
+
// If no override, get the option
|
940 |
+
return get_option( $option_key, $default );
|
941 |
+
}
|
942 |
+
|
943 |
+
/**
|
944 |
+
* Saves the option array
|
945 |
+
* Needs to be run after finished using remove/update_option
|
946 |
+
* @uses apply_filters() Calls 'cmb_override_option_save_$option_key' hook to allow
|
947 |
+
* overwriting the option value to be stored.
|
948 |
+
*
|
949 |
+
* @since 1.0.1
|
950 |
+
* @param string $option_key Option key
|
951 |
+
* @return boolean Success/Failure
|
952 |
+
*/
|
953 |
+
public static function save_option( $option_key ) {
|
954 |
+
|
955 |
+
$to_save = self::get_option( $option_key );
|
956 |
+
|
957 |
+
$test_save = apply_filters( "cmb_override_option_save_$option_key", 'cmb_no_override_option_save', $to_save );
|
958 |
+
|
959 |
+
if ( $test_save !== 'cmb_no_override_option_save' )
|
960 |
+
return $test_save;
|
961 |
+
|
962 |
+
// If no override, update the option
|
963 |
+
return update_option( $option_key, $to_save );
|
964 |
+
}
|
965 |
+
|
966 |
+
/**
|
967 |
+
* Utility method that returns a timezone string representing the default timezone for the site.
|
968 |
+
*
|
969 |
+
* Roughly copied from WordPress, as get_option('timezone_string') will return
|
970 |
+
* and empty string if no value has beens set on the options page.
|
971 |
+
* A timezone string is required by the wp_timezone_choice() used by the
|
972 |
+
* select_timezone field.
|
973 |
+
*
|
974 |
+
* @since 1.0.0
|
975 |
+
* @return string Timezone string
|
976 |
+
*/
|
977 |
+
public static function timezone_string() {
|
978 |
+
$current_offset = get_option( 'gmt_offset' );
|
979 |
+
$tzstring = get_option( 'timezone_string' );
|
980 |
+
|
981 |
+
if ( empty( $tzstring ) ) { // Create a UTC+- zone if no timezone string exists
|
982 |
+
if ( 0 == $current_offset )
|
983 |
+
$tzstring = 'UTC+0';
|
984 |
+
elseif ( $current_offset < 0 )
|
985 |
+
$tzstring = 'UTC' . $current_offset;
|
986 |
+
else
|
987 |
+
$tzstring = 'UTC+' . $current_offset;
|
988 |
+
}
|
989 |
+
|
990 |
+
return $tzstring;
|
991 |
+
}
|
992 |
+
|
993 |
+
/**
|
994 |
+
* Utility method that returns time string offset by timezone
|
995 |
+
* @since 1.0.0
|
996 |
+
* @param string $tzstring Time string
|
997 |
+
* @return string Offset time string
|
998 |
+
*/
|
999 |
+
public static function timezone_offset( $tzstring ) {
|
1000 |
+
if ( ! empty( $tzstring ) && is_string( $tzstring ) ) {
|
1001 |
+
if ( substr( $tzstring, 0, 3 ) === 'UTC' ) {
|
1002 |
+
$tzstring = str_replace( array( ':15',':30',':45' ), array( '.25','.5','.75' ), $tzstring );
|
1003 |
+
return intval( floatval( substr( $tzstring, 3 ) ) * HOUR_IN_SECONDS );
|
1004 |
+
}
|
1005 |
+
|
1006 |
+
$date_time_zone_selected = new DateTimeZone( $tzstring );
|
1007 |
+
$tz_offset = timezone_offset_get( $date_time_zone_selected, date_create() );
|
1008 |
+
|
1009 |
+
return $tz_offset;
|
1010 |
+
}
|
1011 |
+
|
1012 |
+
return 0;
|
1013 |
+
}
|
1014 |
+
|
1015 |
+
/**
|
1016 |
+
* Utility method that attempts to get an attachment's ID by it's url
|
1017 |
+
* @since 1.0.0
|
1018 |
+
* @param string $img_url Attachment url
|
1019 |
+
* @return mixed Attachment ID or false
|
1020 |
+
*/
|
1021 |
+
public static function image_id_from_url( $img_url ) {
|
1022 |
+
global $wpdb;
|
1023 |
+
|
1024 |
+
$img_url = esc_url_raw( $img_url );
|
1025 |
+
// Get just the file name
|
1026 |
+
if ( false !== strpos( $img_url, '/' ) ) {
|
1027 |
+
$explode = explode( '/', $img_url );
|
1028 |
+
$img_url = end( $explode );
|
1029 |
+
}
|
1030 |
+
|
1031 |
+
// And search for a fuzzy match of the file name
|
1032 |
+
$attachment = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE guid LIKE '%%%s%%' LIMIT 1;", $img_url ) );
|
1033 |
+
|
1034 |
+
// If we found an attachement ID, return it
|
1035 |
+
if ( !empty( $attachment ) && is_array( $attachment ) )
|
1036 |
+
return $attachment[0];
|
1037 |
+
|
1038 |
+
// No luck
|
1039 |
+
return false;
|
1040 |
+
}
|
1041 |
+
|
1042 |
+
}
|
1043 |
+
|
1044 |
+
// Handle oembed Ajax
|
1045 |
+
add_action( 'wp_ajax_cmb_oembed_handler', array( 'cmb_Meta_Box_ajax', 'oembed_handler' ) );
|
1046 |
+
add_action( 'wp_ajax_nopriv_cmb_oembed_handler', array( 'cmb_Meta_Box_ajax', 'oembed_handler' ) );
|
1047 |
+
|
1048 |
+
/**
|
1049 |
+
* A helper function to get an option from a CMB options array
|
1050 |
+
* @since 1.0.1
|
1051 |
+
* @param string $option_key Option key
|
1052 |
+
* @param string $field_id Option array field key
|
1053 |
+
* @return array Options array or specific field
|
1054 |
+
*/
|
1055 |
+
function cmb_get_option( $option_key, $field_id = '' ) {
|
1056 |
+
return cmb_Meta_Box::get_option( $option_key, $field_id );
|
1057 |
+
}
|
1058 |
+
|
1059 |
+
/**
|
1060 |
+
* Get a CMB field object.
|
1061 |
+
* @since 1.1.0
|
1062 |
+
* @param array $field_args Field arguments
|
1063 |
+
* @param int $object_id Object ID
|
1064 |
+
* @param string $object_type Type of object being saved. (e.g., post, user, or comment)
|
1065 |
+
* @return object cmb_Meta_Box_field object
|
1066 |
+
*/
|
1067 |
+
function cmb_get_field( $field_args, $object_id = 0, $object_type = 'post' ) {
|
1068 |
+
// Default to the loop post ID
|
1069 |
+
$object_id = $object_id ? $object_id : get_the_ID();
|
1070 |
+
cmb_Meta_Box::set_object_id( $object_id );
|
1071 |
+
cmb_Meta_Box::set_object_type( $object_type );
|
1072 |
+
// Send back field object
|
1073 |
+
return new cmb_Meta_Box_field( $field_args );
|
1074 |
+
}
|
1075 |
+
|
1076 |
+
/**
|
1077 |
+
* Get a field's value.
|
1078 |
+
* @since 1.1.0
|
1079 |
+
* @param array $field_args Field arguments
|
1080 |
+
* @param int $object_id Object ID
|
1081 |
+
* @param string $object_type Type of object being saved. (e.g., post, user, comment, or options-page)
|
1082 |
+
* @return mixed Maybe escaped value
|
1083 |
+
*/
|
1084 |
+
function cmb_get_field_value( $field_args, $object_id = 0, $object_type = 'post' ) {
|
1085 |
+
$field = cmb_get_field( $field_args, $object_id, $object_type );
|
1086 |
+
return $field->escaped_value();
|
1087 |
+
}
|
1088 |
+
|
1089 |
+
/**
|
1090 |
+
* Loop and output multiple metaboxes
|
1091 |
+
* @since 1.0.0
|
1092 |
+
* @param array $meta_boxes Metaboxes config array
|
1093 |
+
* @param int $object_id Object ID
|
1094 |
+
*/
|
1095 |
+
function cmb_print_metaboxes( $meta_boxes, $object_id ) {
|
1096 |
+
foreach ( (array) $meta_boxes as $meta_box ) {
|
1097 |
+
cmb_print_metabox( $meta_box, $object_id );
|
1098 |
+
}
|
1099 |
+
}
|
1100 |
+
|
1101 |
+
/**
|
1102 |
+
* Output a metabox
|
1103 |
+
* @since 1.0.0
|
1104 |
+
* @param array $meta_box Metabox config array
|
1105 |
+
* @param int $object_id Object ID
|
1106 |
+
*/
|
1107 |
+
function cmb_print_metabox( $meta_box, $object_id ) {
|
1108 |
+
$cmb = new cmb_Meta_Box( $meta_box );
|
1109 |
+
if ( $cmb ) {
|
1110 |
+
|
1111 |
+
cmb_Meta_Box::set_object_id( $object_id );
|
1112 |
+
|
1113 |
+
if ( ! wp_script_is( 'cmb-scripts', 'registered' ) )
|
1114 |
+
$cmb->register_scripts();
|
1115 |
+
|
1116 |
+
wp_enqueue_script( 'cmb-scripts' );
|
1117 |
+
|
1118 |
+
// default is to show cmb styles
|
1119 |
+
if ( $meta_box['cmb_styles'] != false )
|
1120 |
+
wp_enqueue_style( 'cmb-styles' );
|
1121 |
+
|
1122 |
+
cmb_Meta_Box::show_form( $meta_box );
|
1123 |
+
}
|
1124 |
+
|
1125 |
+
}
|
1126 |
+
|
1127 |
+
/**
|
1128 |
+
* Saves a particular metabox's fields
|
1129 |
+
* @since 1.0.0
|
1130 |
+
* @param array $meta_box Metabox config array
|
1131 |
+
* @param int $object_id Object ID
|
1132 |
+
*/
|
1133 |
+
function cmb_save_metabox_fields( $meta_box, $object_id ) {
|
1134 |
+
cmb_Meta_Box::save_fields( $meta_box, $object_id );
|
1135 |
+
}
|
1136 |
+
|
1137 |
+
/**
|
1138 |
+
* Display a metabox form & save it on submission
|
1139 |
+
* @since 1.0.0
|
1140 |
+
* @param array $meta_box Metabox config array
|
1141 |
+
* @param int $object_id Object ID
|
1142 |
+
* @param boolean $return Whether to return or echo form
|
1143 |
+
* @return string CMB html form markup
|
1144 |
+
*/
|
1145 |
+
function cmb_metabox_form( $meta_box, $object_id, $echo = true ) {
|
1146 |
+
|
1147 |
+
$meta_box = cmb_Meta_Box::set_mb_defaults( $meta_box );
|
1148 |
+
|
1149 |
+
// Make sure form should be shown
|
1150 |
+
if ( ! apply_filters( 'cmb_show_on', true, $meta_box ) )
|
1151 |
+
return '';
|
1152 |
+
|
1153 |
+
// Make sure that our object type is explicitly set by the metabox config
|
1154 |
+
cmb_Meta_Box::set_object_type( cmb_Meta_Box::set_mb_type( $meta_box ) );
|
1155 |
+
|
1156 |
+
// Save the metabox if it's been submitted
|
1157 |
+
// check permissions
|
1158 |
+
// @todo more hardening?
|
1159 |
+
if (
|
1160 |
+
// check nonce
|
1161 |
+
isset( $_POST['submit-cmb'], $_POST['object_id'], $_POST['wp_meta_box_nonce'] )
|
1162 |
+
&& wp_verify_nonce( $_POST['wp_meta_box_nonce'], cmb_Meta_Box::nonce() )
|
1163 |
+
&& $_POST['object_id'] == $object_id
|
1164 |
+
)
|
1165 |
+
cmb_save_metabox_fields( $meta_box, $object_id );
|
1166 |
+
|
1167 |
+
// Show specific metabox form
|
1168 |
+
|
1169 |
+
// Get cmb form
|
1170 |
+
ob_start();
|
1171 |
+
cmb_print_metabox( $meta_box, $object_id );
|
1172 |
+
$form = ob_get_contents();
|
1173 |
+
ob_end_clean();
|
1174 |
+
|
1175 |
+
$form_format = apply_filters( 'cmb_frontend_form_format', '<form class="cmb-form" method="post" id="%s" enctype="multipart/form-data" encoding="multipart/form-data"><input type="hidden" name="object_id" value="%s">%s<input type="submit" name="submit-cmb" value="%s" class="button-primary"></form>', $object_id, $meta_box, $form );
|
1176 |
+
|
1177 |
+
$form = sprintf( $form_format, $meta_box['id'], $object_id, $form, __( 'Save' ) );
|
1178 |
+
|
1179 |
+
if ( $echo )
|
1180 |
+
echo $form;
|
1181 |
+
|
1182 |
+
return $form;
|
1183 |
+
}
|
1184 |
+
|
1185 |
+
// End. That's it, folks! //
|
lib/cmb_metaboxes/js/cmb.js
CHANGED
@@ -1,797 +1,797 @@
|
|
1 |
-
/**
|
2 |
-
* Controls the behaviours of custom metabox fields.
|
3 |
-
*
|
4 |
-
* @author Andrew Norcross
|
5 |
-
* @author Jared Atchison
|
6 |
-
* @author Bill Erickson
|
7 |
-
* @author Justin Sternberg
|
8 |
-
* @see https://github.com/webdevstudios/Custom-Metaboxes-and-Fields-for-WordPress
|
9 |
-
*/
|
10 |
-
|
11 |
-
/**
|
12 |
-
* Custom jQuery for Custom Metaboxes and Fields
|
13 |
-
*/
|
14 |
-
window.CMB = (function(window, document, $, undefined){
|
15 |
-
'use strict';
|
16 |
-
|
17 |
-
// localization strings
|
18 |
-
var l10n = window.cmb_l10;
|
19 |
-
var setTimeout = window.setTimeout;
|
20 |
-
|
21 |
-
// CMB functionality object
|
22 |
-
var cmb = {
|
23 |
-
formfield : '',
|
24 |
-
idNumber : false,
|
25 |
-
file_frames : {},
|
26 |
-
repeatEls : 'input:not([type="button"]),select,textarea,.cmb_media_status'
|
27 |
-
};
|
28 |
-
|
29 |
-
cmb.metabox = function() {
|
30 |
-
if ( cmb.$metabox ) {
|
31 |
-
return cmb.$metabox;
|
32 |
-
}
|
33 |
-
cmb.$metabox = $('table.cmb_metabox');
|
34 |
-
return cmb.$metabox;
|
35 |
-
};
|
36 |
-
|
37 |
-
cmb.init = function() {
|
38 |
-
|
39 |
-
var $metabox = cmb.metabox();
|
40 |
-
var $repeatGroup = $metabox.find('.repeatable-group');
|
41 |
-
|
42 |
-
// hide our spinner gif if we're on a MP6 dashboard
|
43 |
-
if ( l10n.new_admin_style ) {
|
44 |
-
$metabox.find('.cmb-spinner img').hide();
|
45 |
-
}
|
46 |
-
|
47 |
-
/**
|
48 |
-
* Initialize time/date/color pickers
|
49 |
-
*/
|
50 |
-
cmb.initPickers( $metabox.find('input:text.cmb_timepicker'), $metabox.find('input:text.cmb_datepicker'), $metabox.find('input:text.cmb_colorpicker') );
|
51 |
-
|
52 |
-
// Wrap date picker in class to narrow the scope of jQuery UI CSS and prevent conflicts
|
53 |
-
$("#ui-datepicker-div").wrap('<div class="cmb_element" />');
|
54 |
-
|
55 |
-
// Insert toggle button into DOM wherever there is multicheck. credit: Genesis Framework
|
56 |
-
$( '<p><span class="button cmb-multicheck-toggle">' + l10n.check_toggle + '</span></p>' ).insertBefore( 'ul.cmb_checkbox_list' );
|
57 |
-
|
58 |
-
$metabox
|
59 |
-
.on( 'change', '.cmb_upload_file', function() {
|
60 |
-
cmb.formfield = $(this).attr('id');
|
61 |
-
$('#' + cmb.formfield + '_id').val('');
|
62 |
-
})
|
63 |
-
// Media/file management
|
64 |
-
.on( 'click', '.cmb-multicheck-toggle', cmb.toggleCheckBoxes )
|
65 |
-
.on( 'click', '.cmb_upload_button', cmb.handleMedia )
|
66 |
-
.on( 'click', '.cmb_remove_file_button', cmb.handleRemoveMedia )
|
67 |
-
// Repeatable content
|
68 |
-
.on( 'click', '.add-group-row', cmb.addGroupRow )
|
69 |
-
.on( 'click', '.add-row-button', cmb.addAjaxRow )
|
70 |
-
.on( 'click', '.remove-group-row', cmb.removeGroupRow )
|
71 |
-
.on( 'click', '.remove-row-button', cmb.removeAjaxRow )
|
72 |
-
// Ajax oEmbed display
|
73 |
-
.on( 'keyup paste focusout', '.cmb_oembed', cmb.maybeOembed )
|
74 |
-
// Reset titles when removing a row
|
75 |
-
.on( 'cmb_remove_row', '.repeatable-group', cmb.resetTitlesAndIterator );
|
76 |
-
|
77 |
-
if ( $repeatGroup.length ) {
|
78 |
-
$repeatGroup
|
79 |
-
.filter('.sortable').each( function() {
|
80 |
-
// Add sorting arrows
|
81 |
-
$(this).find( '.remove-group-row' ).before( '<a class="shift-rows move-up alignleft" href="#">'+ l10n.up_arrow +'</a> <a class="shift-rows move-down alignleft" href="#">'+ l10n.down_arrow +'</a>' );
|
82 |
-
})
|
83 |
-
.on( 'click', '.shift-rows', cmb.shiftRows )
|
84 |
-
.on( 'cmb_add_row', cmb.emptyValue );
|
85 |
-
}
|
86 |
-
|
87 |
-
// on pageload
|
88 |
-
setTimeout( cmb.resizeoEmbeds, 500);
|
89 |
-
// and on window resize
|
90 |
-
$(window).on( 'resize', cmb.resizeoEmbeds );
|
91 |
-
|
92 |
-
};
|
93 |
-
|
94 |
-
cmb.resetTitlesAndIterator = function() {
|
95 |
-
// Loop repeatable group tables
|
96 |
-
$( '.repeatable-group' ).each( function() {
|
97 |
-
var $table = $(this);
|
98 |
-
// Loop repeatable group table rows
|
99 |
-
$table.find( '.repeatable-grouping' ).each( function( rowindex ) {
|
100 |
-
var $row = $(this);
|
101 |
-
// Reset rows iterator
|
102 |
-
$row.data( 'iterator', rowindex );
|
103 |
-
// Reset rows title
|
104 |
-
$row.find( '.cmb-group-title h4' ).text( $table.find( '.add-group-row' ).data( 'grouptitle' ).replace( '{#}', ( rowindex + 1 ) ) );
|
105 |
-
});
|
106 |
-
});
|
107 |
-
};
|
108 |
-
|
109 |
-
cmb.toggleCheckBoxes = function( event ) {
|
110 |
-
event.preventDefault();
|
111 |
-
var $self = $(this);
|
112 |
-
var $multicheck = $self.parents( 'td' ).find( 'input[type=checkbox]' );
|
113 |
-
|
114 |
-
// If the button has already been clicked once...
|
115 |
-
if ( $self.data( 'checked' ) ) {
|
116 |
-
// clear the checkboxes and remove the flag
|
117 |
-
$multicheck.prop( 'checked', false );
|
118 |
-
$self.data( 'checked', false );
|
119 |
-
}
|
120 |
-
// Otherwise mark the checkboxes and add a flag
|
121 |
-
else {
|
122 |
-
$multicheck.prop( 'checked', true );
|
123 |
-
$self.data( 'checked', true );
|
124 |
-
}
|
125 |
-
};
|
126 |
-
|
127 |
-
cmb.handleMedia = function(event) {
|
128 |
-
|
129 |
-
if ( ! wp ) {
|
130 |
-
return;
|
131 |
-
}
|
132 |
-
|
133 |
-
event.preventDefault();
|
134 |
-
|
135 |
-
var $metabox = cmb.metabox();
|
136 |
-
var $self = $(this);
|
137 |
-
cmb.formfield = $self.prev('input').attr('id');
|
138 |
-
var $formfield = $('#'+cmb.formfield);
|
139 |
-
var formName = $formfield.attr('name');
|
140 |
-
var uploadStatus = true;
|
141 |
-
var attachment = true;
|
142 |
-
var isList = $self.hasClass( 'cmb_upload_list' );
|
143 |
-
|
144 |
-
// If this field's media frame already exists, reopen it.
|
145 |
-
if ( cmb.formfield in cmb.file_frames ) {
|
146 |
-
cmb.file_frames[cmb.formfield].open();
|
147 |
-
return;
|
148 |
-
}
|
149 |
-
|
150 |
-
// Create the media frame.
|
151 |
-
cmb.file_frames[cmb.formfield] = wp.media.frames.file_frame = wp.media({
|
152 |
-
title: $metabox.find('label[for=' + cmb.formfield + ']').text(),
|
153 |
-
button: {
|
154 |
-
text: l10n.upload_file
|
155 |
-
},
|
156 |
-
multiple: isList ? true : false
|
157 |
-
});
|
158 |
-
|
159 |
-
var handlers = {
|
160 |
-
list : function( selection ) {
|
161 |
-
// Get all of our selected files
|
162 |
-
attachment = selection.toJSON();
|
163 |
-
|
164 |
-
$formfield.val(attachment.url);
|
165 |
-
$('#'+ cmb.formfield +'_id').val(attachment.id);
|
166 |
-
|
167 |
-
// Setup our fileGroup array
|
168 |
-
var fileGroup = [];
|
169 |
-
|
170 |
-
// Loop through each attachment
|
171 |
-
$( attachment ).each( function() {
|
172 |
-
if ( this.type && this.type === 'image' ) {
|
173 |
-
// image preview
|
174 |
-
uploadStatus = '<li class="img_status">'+
|
175 |
-
'<img width="50" height="50" src="' + this.url + '" class="attachment-50x50" alt="'+ this.filename +'">'+
|
176 |
-
'<p><a href="#" class="cmb_remove_file_button" rel="'+ cmb.formfield +'['+ this.id +']">'+ l10n.remove_image +'</a></p>'+
|
177 |
-
'<input type="hidden" id="filelist-'+ this.id +'" name="'+ formName +'['+ this.id +']" value="' + this.url + '">'+
|
178 |
-
'</li>';
|
179 |
-
|
180 |
-
} else {
|
181 |
-
// Standard generic output if it's not an image.
|
182 |
-
uploadStatus = '<li>'+ l10n.file +' <strong>'+ this.filename +'</strong> (<a href="' + this.url + '" target="_blank" rel="external">'+ l10n.download +'</a> / <a href="#" class="cmb_remove_file_button" rel="'+ cmb.formfield +'['+ this.id +']">'+ l10n.remove_file +'</a>)'+
|
183 |
-
'<input type="hidden" id="filelist-'+ this.id +'" name="'+ formName +'['+ this.id +']" value="' + this.url + '">'+
|
184 |
-
'</li>';
|
185 |
-
|
186 |
-
}
|
187 |
-
|
188 |
-
// Add our file to our fileGroup array
|
189 |
-
fileGroup.push( uploadStatus );
|
190 |
-
});
|
191 |
-
|
192 |
-
// Append each item from our fileGroup array to .cmb_media_status
|
193 |
-
$( fileGroup ).each( function() {
|
194 |
-
$formfield.siblings('.cmb_media_status').slideDown().append(this);
|
195 |
-
});
|
196 |
-
},
|
197 |
-
single : function( selection ) {
|
198 |
-
// Only get one file from the uploader
|
199 |
-
attachment = selection.first().toJSON();
|
200 |
-
|
201 |
-
$formfield.val(attachment.url);
|
202 |
-
$('#'+ cmb.formfield +'_id').val(attachment.id);
|
203 |
-
|
204 |
-
if ( attachment.type && attachment.type === 'image' ) {
|
205 |
-
// image preview
|
206 |
-
uploadStatus = '<div class="img_status"><img style="max-width: 350px; width: 100%; height: auto;" src="' + attachment.url + '" alt="'+ attachment.filename +'" title="'+ attachment.filename +'" /><p><a href="#" class="cmb_remove_file_button" rel="' + cmb.formfield + '">'+ l10n.remove_image +'</a></p></div>';
|
207 |
-
} else {
|
208 |
-
// Standard generic output if it's not an image.
|
209 |
-
uploadStatus = l10n.file +' <strong>'+ attachment.filename +'</strong> (<a href="'+ attachment.url +'" target="_blank" rel="external">'+ l10n.download +'</a> / <a href="#" class="cmb_remove_file_button" rel="'+ cmb.formfield +'">'+ l10n.remove_file +'</a>)';
|
210 |
-
}
|
211 |
-
|
212 |
-
// add/display our output
|
213 |
-
$formfield.siblings('.cmb_media_status').slideDown().html(uploadStatus);
|
214 |
-
}
|
215 |
-
};
|
216 |
-
|
217 |
-
// When an file is selected, run a callback.
|
218 |
-
cmb.file_frames[cmb.formfield].on( 'select', function() {
|
219 |
-
var selection = cmb.file_frames[cmb.formfield].state().get('selection');
|
220 |
-
var type = isList ? 'list' : 'single';
|
221 |
-
handlers[type]( selection );
|
222 |
-
});
|
223 |
-
|
224 |
-
// Finally, open the modal
|
225 |
-
cmb.file_frames[cmb.formfield].open();
|
226 |
-
};
|
227 |
-
|
228 |
-
cmb.handleRemoveMedia = function( event ) {
|
229 |
-
event.preventDefault();
|
230 |
-
var $self = $(this);
|
231 |
-
if ( $self.is( '.attach_list .cmb_remove_file_button' ) ){
|
232 |
-
$self.parents('li').remove();
|
233 |
-
return false;
|
234 |
-
}
|
235 |
-
cmb.formfield = $self.attr('rel');
|
236 |
-
var $container = $self.parents('.img_status');
|
237 |
-
|
238 |
-
cmb.metabox().find('input#' + cmb.formfield).val('');
|
239 |
-
cmb.metabox().find('input#' + cmb.formfield + '_id').val('');
|
240 |
-
if ( ! $container.length ) {
|
241 |
-
$self.parents('.cmb_media_status').html('');
|
242 |
-
} else {
|
243 |
-
$container.html('');
|
244 |
-
}
|
245 |
-
return false;
|
246 |
-
};
|
247 |
-
|
248 |
-
// src: http://www.benalman.com/projects/jquery-replacetext-plugin/
|
249 |
-
$.fn.replaceText = function(b, a, c) {
|
250 |
-
return this.each(function() {
|
251 |
-
var f = this.firstChild, g, e, d = [];
|
252 |
-
if (f) {
|
253 |
-
do {
|
254 |
-
if (f.nodeType === 3) {
|
255 |
-
g = f.nodeValue;
|
256 |
-
e = g.replace(b, a);
|
257 |
-
if (e !== g) {
|
258 |
-
if (!c && /</.test(e)) {
|
259 |
-
$(f).before(e);
|
260 |
-
d.push(f);
|
261 |
-
} else {
|
262 |
-
f.nodeValue = e;
|
263 |
-
}
|
264 |
-
}
|
265 |
-
}
|
266 |
-
} while (f = f.nextSibling);
|
267 |
-
}
|
268 |
-
if ( d.length ) { $(d).remove(); }
|
269 |
-
});
|
270 |
-
};
|
271 |
-
|
272 |
-
$.fn.cleanRow = function( prevNum, group ) {
|
273 |
-
var $self = $(this);
|
274 |
-
var $inputs = $self.find('input:not([type="button"]), select, textarea, label');
|
275 |
-
if ( group ) {
|
276 |
-
// Remove extra ajaxed rows
|
277 |
-
$self.find('.cmb-repeat-table .repeat-row:not(:first-child)').remove();
|
278 |
-
}
|
279 |
-
cmb.$focus = false;
|
280 |
-
cmb.neweditor_id = [];
|
281 |
-
|
282 |
-
$inputs.filter(':checked').removeAttr( 'checked' );
|
283 |
-
$inputs.filter(':selected').removeAttr( 'selected' );
|
284 |
-
|
285 |
-
if ( $self.find('.cmb-group-title') ) {
|
286 |
-
$self.find( '.cmb-group-title h4' ).text( $self.data( 'title' ).replace( '{#}', ( cmb.idNumber + 1 ) ) );
|
287 |
-
}
|
288 |
-
|
289 |
-
$inputs.each( function(){
|
290 |
-
var $newInput = $(this);
|
291 |
-
var isEditor = $newInput.hasClass( 'wp-editor-area' );
|
292 |
-
var oldFor = $newInput.attr( 'for' );
|
293 |
-
// var $next = $newInput.next();
|
294 |
-
var attrs = {};
|
295 |
-
var newID, oldID;
|
296 |
-
if ( oldFor ) {
|
297 |
-
attrs = { 'for' : oldFor.replace( '_'+ prevNum, '_'+ cmb.idNumber ) };
|
298 |
-
} else {
|
299 |
-
var oldName = $newInput.attr( 'name' );
|
300 |
-
// Replace 'name' attribute key
|
301 |
-
var newName = oldName ? oldName.replace( '['+ prevNum +']', '['+ cmb.idNumber +']' ) : '';
|
302 |
-
oldID = $newInput.attr( 'id' );
|
303 |
-
newID = oldID ? oldID.replace( '_'+ prevNum, '_'+ cmb.idNumber ) : '';
|
304 |
-
attrs = {
|
305 |
-
id: newID,
|
306 |
-
name: newName,
|
307 |
-
// value: '',
|
308 |
-
'data-iterator': cmb.idNumber,
|
309 |
-
};
|
310 |
-
}
|
311 |
-
|
312 |
-
$newInput
|
313 |
-
.removeClass( 'hasDatepicker' )
|
314 |
-
.attr( attrs ).val('');
|
315 |
-
|
316 |
-
// wysiwyg field
|
317 |
-
if ( isEditor ) {
|
318 |
-
// Get new wysiwyg ID
|
319 |
-
newID = newID ? oldID.replace( 'zx'+ prevNum, 'zx'+ cmb.idNumber ) : '';
|
320 |
-
// Empty the contents
|
321 |
-
$newInput.html('');
|
322 |
-
// Get wysiwyg field
|
323 |
-
var $wysiwyg = $newInput.parents( '.cmb-type-wysiwyg' );
|
324 |
-
// Remove extra mce divs
|
325 |
-
$wysiwyg.find('.mce-tinymce:not(:first-child)').remove();
|
326 |
-
// Replace id instances
|
327 |
-
var html = $wysiwyg.html().replace( new RegExp( oldID, 'g' ), newID );
|
328 |
-
// Update field html
|
329 |
-
$wysiwyg.html( html );
|
330 |
-
// Save ids for later to re-init tinymce
|
331 |
-
cmb.neweditor_id.push( { 'id': newID, 'old': oldID } );
|
332 |
-
}
|
333 |
-
|
334 |
-
cmb.$focus = cmb.$focus ? cmb.$focus : $newInput;
|
335 |
-
});
|
336 |
-
|
337 |
-
return this;
|
338 |
-
};
|
339 |
-
|
340 |
-
$.fn.newRowHousekeeping = function() {
|
341 |
-
var $row = $(this);
|
342 |
-
var $colorPicker = $row.find( '.wp-picker-container' );
|
343 |
-
var $list = $row.find( '.cmb_media_status' );
|
344 |
-
|
345 |
-
if ( $colorPicker.length ) {
|
346 |
-
// Need to clean-up colorpicker before appending
|
347 |
-
$colorPicker.each( function() {
|
348 |
-
var $td = $(this).parent();
|
349 |
-
$td.html( $td.find( 'input:text.cmb_colorpicker' ).attr('style', '') );
|
350 |
-
});
|
351 |
-
}
|
352 |
-
|
353 |
-
// Need to clean-up colorpicker before appending
|
354 |
-
if ( $list.length ) {
|
355 |
-
$list.empty();
|
356 |
-
}
|
357 |
-
|
358 |
-
return this;
|
359 |
-
};
|
360 |
-
|
361 |
-
cmb.afterRowInsert = function( $row ) {
|
362 |
-
if ( cmb.$focus ) {
|
363 |
-
cmb.$focus.focus();
|
364 |
-
}
|
365 |
-
|
366 |
-
var _prop;
|
367 |
-
|
368 |
-
// Need to re-init wp_editor instances
|
369 |
-
if ( cmb.neweditor_id.length ) {
|
370 |
-
var i;
|
371 |
-
for ( i = cmb.neweditor_id.length - 1; i >= 0; i-- ) {
|
372 |
-
var id = cmb.neweditor_id[i].id;
|
373 |
-
var old = cmb.neweditor_id[i].old;
|
374 |
-
|
375 |
-
if ( typeof( tinyMCEPreInit.mceInit[ id ] ) === 'undefined' ) {
|
376 |
-
var newSettings = jQuery.extend( {}, tinyMCEPreInit.mceInit[ old ] );
|
377 |
-
|
378 |
-
for ( _prop in newSettings ) {
|
379 |
-
if ( 'string' === typeof( newSettings[_prop] ) ) {
|
380 |
-
newSettings[_prop] = newSettings[_prop].replace( new RegExp( old, 'g' ), id );
|
381 |
-
}
|
382 |
-
}
|
383 |
-
tinyMCEPreInit.mceInit[ id ] = newSettings;
|
384 |
-
}
|
385 |
-
if ( typeof( tinyMCEPreInit.qtInit[ id ] ) === 'undefined' ) {
|
386 |
-
var newQTS = jQuery.extend( {}, tinyMCEPreInit.qtInit[ old ] );
|
387 |
-
for ( _prop in newQTS ) {
|
388 |
-
if ( 'string' === typeof( newQTS[_prop] ) ) {
|
389 |
-
newQTS[_prop] = newQTS[_prop].replace( new RegExp( old, 'g' ), id );
|
390 |
-
}
|
391 |
-
}
|
392 |
-
tinyMCEPreInit.qtInit[ id ] = newQTS;
|
393 |
-
}
|
394 |
-
tinyMCE.init({
|
395 |
-
id : tinyMCEPreInit.mceInit[ id ],
|
396 |
-
});
|
397 |
-
|
398 |
-
}
|
399 |
-
}
|
400 |
-
|
401 |
-
// Init pickers from new row
|
402 |
-
cmb.initPickers( $row.find('input:text.cmb_timepicker'), $row.find('input:text.cmb_datepicker'), $row.find('input:text.cmb_colorpicker') );
|
403 |
-
};
|
404 |
-
|
405 |
-
cmb.updateNameAttr = function () {
|
406 |
-
|
407 |
-
var $this = $(this);
|
408 |
-
var name = $this.attr( 'name' ); // get current name
|
409 |
-
|
410 |
-
// No name? bail
|
411 |
-
if ( typeof name === 'undefined' ) {
|
412 |
-
return false;
|
413 |
-
}
|
414 |
-
|
415 |
-
var prevNum = parseInt( $this.parents( '.repeatable-grouping' ).data( 'iterator' ) );
|
416 |
-
var newNum = prevNum - 1; // Subtract 1 to get new iterator number
|
417 |
-
|
418 |
-
// Update field name attributes so data is not orphaned when a row is removed and post is saved
|
419 |
-
var $newName = name.replace( '[' + prevNum + ']', '[' + newNum + ']' );
|
420 |
-
|
421 |
-
// New name with replaced iterator
|
422 |
-
$this.attr( 'name', $newName );
|
423 |
-
|
424 |
-
};
|
425 |
-
|
426 |
-
cmb.emptyValue = function( event, row ) {
|
427 |
-
$('input:not([type="button"]), textarea', row).val('');
|
428 |
-
};
|
429 |
-
|
430 |
-
cmb.addGroupRow = function( event ) {
|
431 |
-
|
432 |
-
event.preventDefault();
|
433 |
-
|
434 |
-
var $self = $(this);
|
435 |
-
var $table = $('#'+ $self.data('selector'));
|
436 |
-
var $oldRow = $table.find('.repeatable-grouping').last();
|
437 |
-
var prevNum = parseInt( $oldRow.data('iterator') );
|
438 |
-
cmb.idNumber = prevNum + 1;
|
439 |
-
var $row = $oldRow.clone();
|
440 |
-
|
441 |
-
$row.data( 'title', $self.data( 'grouptitle' ) ).newRowHousekeeping().cleanRow( prevNum, true );
|
442 |
-
|
443 |
-
// console.log( '$row.html()', $row.html() );
|
444 |
-
var $newRow = $( '<tr class="repeatable-grouping" data-iterator="'+ cmb.idNumber +'">'+ $row.html() +'</tr>' );
|
445 |
-
$oldRow.after( $newRow );
|
446 |
-
// console.log( '$newRow.html()', $row.html() );
|
447 |
-
|
448 |
-
cmb.afterRowInsert( $newRow );
|
449 |
-
|
450 |
-
if ( $table.find('.repeatable-grouping').length <= 1 ) {
|
451 |
-
$table.find('.remove-group-row').prop('disabled', true);
|
452 |
-
} else {
|
453 |
-
$table.find('.remove-group-row').removeAttr( 'disabled' );
|
454 |
-
}
|
455 |
-
|
456 |
-
$table.trigger( 'cmb_add_row', $newRow );
|
457 |
-
};
|
458 |
-
|
459 |
-
cmb.addAjaxRow = function( event ) {
|
460 |
-
|
461 |
-
event.preventDefault();
|
462 |
-
|
463 |
-
var $self = $(this);
|
464 |
-
var tableselector = '#'+ $self.data('selector');
|
465 |
-
var $table = $(tableselector);
|
466 |
-
var $emptyrow = $table.find('.empty-row');
|
467 |
-
var prevNum = parseInt( $emptyrow.find('[data-iterator]').data('iterator') );
|
468 |
-
cmb.idNumber = prevNum + 1;
|
469 |
-
var $row = $emptyrow.clone();
|
470 |
-
|
471 |
-
$row.newRowHousekeeping().cleanRow( prevNum );
|
472 |
-
|
473 |
-
$emptyrow.removeClass('empty-row').addClass('repeat-row');
|
474 |
-
$emptyrow.after( $row );
|
475 |
-
|
476 |
-
cmb.afterRowInsert( $row );
|
477 |
-
$table.trigger( 'cmb_add_row', $row );
|
478 |
-
};
|
479 |
-
|
480 |
-
cmb.removeGroupRow = function( event ) {
|
481 |
-
event.preventDefault();
|
482 |
-
var $self = $(this);
|
483 |
-
var $table = $('#'+ $self.data('selector'));
|
484 |
-
var $parent = $self.parents('.repeatable-grouping');
|
485 |
-
var noRows = $table.find('.repeatable-grouping').length;
|
486 |
-
|
487 |
-
// when a group is removed loop through all next groups and update fields names
|
488 |
-
$parent.nextAll( '.repeatable-grouping' ).find( cmb.repeatEls ).each( cmb.updateNameAttr );
|
489 |
-
|
490 |
-
if ( noRows > 1 ) {
|
491 |
-
$parent.remove();
|
492 |
-
if ( noRows < 3 ) {
|
493 |
-
$table.find('.remove-group-row').prop('disabled', true);
|
494 |
-
} else {
|
495 |
-
$table.find('.remove-group-row').prop('disabled', false);
|
496 |
-
}
|
497 |
-
$table.trigger( 'cmb_remove_row' );
|
498 |
-
}
|
499 |
-
};
|
500 |
-
|
501 |
-
cmb.removeAjaxRow = function( event ) {
|
502 |
-
event.preventDefault();
|
503 |
-
var $self = $(this);
|
504 |
-
var $parent = $self.parents('tr');
|
505 |
-
var $table = $self.parents('.cmb-repeat-table');
|
506 |
-
|
507 |
-
// cmb.log( 'number of tbodys', $table.length );
|
508 |
-
// cmb.log( 'number of trs', $('tr', $table).length );
|
509 |
-
if ( $table.find('tr').length > 1 ) {
|
510 |
-
if ( $parent.hasClass('empty-row') ) {
|
511 |
-
$parent.prev().addClass( 'empty-row' ).removeClass('repeat-row');
|
512 |
-
}
|
513 |
-
$self.parents('.cmb-repeat-table tr').remove();
|
514 |
-
$table.trigger( 'cmb_remove_row' );
|
515 |
-
}
|
516 |
-
};
|
517 |
-
|
518 |
-
cmb.shiftRows = function( event ) {
|
519 |
-
|
520 |
-
event.preventDefault();
|
521 |
-
|
522 |
-
var $self = $(this);
|
523 |
-
var $parent = $self.parents( '.repeatable-grouping' );
|
524 |
-
var $goto = $self.hasClass( 'move-up' ) ? $parent.prev( '.repeatable-grouping' ) : $parent.next( '.repeatable-grouping' );
|
525 |
-
|
526 |
-
if ( ! $goto.length ) {
|
527 |
-
return;
|
528 |
-
}
|
529 |
-
|
530 |
-
var inputVals = [];
|
531 |
-
// Loop this items fields
|
532 |
-
$parent.find( cmb.repeatEls ).each( function() {
|
533 |
-
var $element = $(this);
|
534 |
-
var val;
|
535 |
-
if ( $element.hasClass('cmb_media_status') ) {
|
536 |
-
// special case for image previews
|
537 |
-
val = $element.html();
|
538 |
-
} else if ( 'checkbox' === $element.attr('type') ) {
|
539 |
-
val = $element.is(':checked');
|
540 |
-
cmb.log( 'checked', val );
|
541 |
-
} else if ( 'select' === $element.prop('tagName') ) {
|
542 |
-
val = $element.is(':selected');
|
543 |
-
cmb.log( 'checked', val );
|
544 |
-
} else {
|
545 |
-
val = $element.val();
|
546 |
-
}
|
547 |
-
// Get all the current values per element
|
548 |
-
inputVals.push( { val: val, $: $element } );
|
549 |
-
});
|
550 |
-
// And swap them all
|
551 |
-
$goto.find( cmb.repeatEls ).each( function( index ) {
|
552 |
-
var $element = $(this);
|
553 |
-
var val;
|
554 |
-
|
555 |
-
if ( $element.hasClass('cmb_media_status') ) {
|
556 |
-
// special case for image previews
|
557 |
-
val = $element.html();
|
558 |
-
$element.html( inputVals[ index ]['val'] );
|
559 |
-
inputVals[ index ]['$'].html( val );
|
560 |
-
|
561 |
-
}
|
562 |
-
// handle checkbox swapping
|
563 |
-
else if ( 'checkbox' === $element.attr('type') ) {
|
564 |
-
inputVals[ index ]['$'].prop( 'checked', $element.is(':checked') );
|
565 |
-
$element.prop( 'checked', inputVals[ index ]['val'] );
|
566 |
-
}
|
567 |
-
// handle select swapping
|
568 |
-
else if ( 'select' === $element.prop('tagName') ) {
|
569 |
-
inputVals[ index ]['$'].prop( 'selected', $element.is(':selected') );
|
570 |
-
$element.prop( 'selected', inputVals[ index ]['val'] );
|
571 |
-
}
|
572 |
-
// handle normal input swapping
|
573 |
-
else {
|
574 |
-
inputVals[ index ]['$'].val( $element.val() );
|
575 |
-
$element.val( inputVals[ index ]['val'] );
|
576 |
-
}
|
577 |
-
});
|
578 |
-
};
|
579 |
-
|
580 |
-
/**
|
581 |
-
* @todo make work, always
|
582 |
-
*/
|
583 |
-
cmb.initPickers = function( $timePickers, $datePickers, $colorPickers ) {
|
584 |
-
// Initialize timepicker
|
585 |
-
cmb.initTimePickers( $timePickers );
|
586 |
-
|
587 |
-
// Initialize jQuery UI datepicker
|
588 |
-
cmb.initDatePickers( $datePickers );
|
589 |
-
|
590 |
-
// Initialize color picker
|
591 |
-
cmb.initColorPickers( $colorPickers );
|
592 |
-
};
|
593 |
-
|
594 |
-
cmb.initTimePickers = function( $selector ) {
|
595 |
-
if ( ! $selector.length ) {
|
596 |
-
return;
|
597 |
-
}
|
598 |
-
|
599 |
-
$selector.timePicker({
|
600 |
-
startTime: "00:00",
|
601 |
-
endTime: "23:59",
|
602 |
-
show24Hours: false,
|
603 |
-
separator: ':',
|
604 |
-
step: 30
|
605 |
-
});
|
606 |
-
};
|
607 |
-
|
608 |
-
cmb.initDatePickers = function( $selector ) {
|
609 |
-
if ( ! $selector.length ) {
|
610 |
-
return;
|
611 |
-
}
|
612 |
-
|
613 |
-
$selector.datepicker( "destroy" );
|
614 |
-
$selector.datepicker();
|
615 |
-
};
|
616 |
-
|
617 |
-
cmb.initColorPickers = function( $selector ) {
|
618 |
-
if ( ! $selector.length ) {
|
619 |
-
return;
|
620 |
-
}
|
621 |
-
if (typeof jQuery.wp === 'object' && typeof jQuery.wp.wpColorPicker === 'function') {
|
622 |
-
|
623 |
-
$selector.wpColorPicker();
|
624 |
-
|
625 |
-
} else {
|
626 |
-
$selector.each( function(i) {
|
627 |
-
$(this).after('<div id="picker-' + i + '" style="z-index: 1000; background: #EEE; border: 1px solid #CCC; position: absolute; display: block;"></div>');
|
628 |
-
$('#picker-' + i).hide().farbtastic($(this));
|
629 |
-
})
|
630 |
-
.focus( function() {
|
631 |
-
$(this).next().show();
|
632 |
-
})
|
633 |
-
.blur( function() {
|
634 |
-
$(this).next().hide();
|
635 |
-
});
|
636 |
-
}
|
637 |
-
};
|
638 |
-
|
639 |
-
cmb.maybeOembed = function( evt ) {
|
640 |
-
var $self = $(this);
|
641 |
-
var type = evt.type;
|
642 |
-
|
643 |
-
var m = {
|
644 |
-
focusout : function() {
|
645 |
-
setTimeout( function() {
|
646 |
-
// if it's been 2 seconds, hide our spinner
|
647 |
-
cmb.spinner( '.postbox table.cmb_metabox', true );
|
648 |
-
}, 2000);
|
649 |
-
},
|
650 |
-
keyup : function() {
|
651 |
-
var betw = function( min, max ) {
|
652 |
-
return ( evt.which <= max && evt.which >= min );
|
653 |
-
};
|
654 |
-
// Only Ajax on normal keystrokes
|
655 |
-
if ( betw( 48, 90 ) || betw( 96, 111 ) || betw( 8, 9 ) || evt.which === 187 || evt.which === 190 ) {
|
656 |
-
// fire our ajax function
|
657 |
-
cmb.doAjax( $self, evt);
|
658 |
-
}
|
659 |
-
},
|
660 |
-
paste : function() {
|
661 |
-
// paste event is fired before the value is filled, so wait a bit
|
662 |
-
setTimeout( function() { cmb.doAjax( $self ); }, 100);
|
663 |
-
}
|
664 |
-
};
|
665 |
-
m[type]();
|
666 |
-
|
667 |
-
};
|
668 |
-
|
669 |
-
/**
|
670 |
-
* Resize oEmbed videos to fit in their respective metaboxes
|
671 |
-
*/
|
672 |
-
cmb.resizeoEmbeds = function() {
|
673 |
-
cmb.metabox().each( function() {
|
674 |
-
var $self = $(this);
|
675 |
-
var $tableWrap = $self.parents('.inside');
|
676 |
-
if ( ! $tableWrap.length ) {
|
677 |
-
return true; // continue
|
678 |
-
}
|
679 |
-
|
680 |
-
// Calculate new width
|
681 |
-
var newWidth = Math.round(($tableWrap.width() * 0.82)*0.97) - 30;
|
682 |
-
if ( newWidth > 639 ) {
|
683 |
-
return true; // continue
|
684 |
-
}
|
685 |
-
|
686 |
-
var $embeds = $self.find('.cmb-type-oembed .embed_status');
|
687 |
-
var $children = $embeds.children().not('.cmb_remove_wrapper');
|
688 |
-
if ( ! $children.length ) {
|
689 |
-
return true; // continue
|
690 |
-
}
|
691 |
-
|
692 |
-
$children.each( function() {
|
693 |
-
var $self = $(this);
|
694 |
-
var iwidth = $self.width();
|
695 |
-
var iheight = $self.height();
|
696 |
-
var _newWidth = newWidth;
|
697 |
-
if ( $self.parents( '.repeat-row' ).length ) {
|
698 |
-
// Make room for our repeatable "remove" button column
|
699 |
-
_newWidth = newWidth - 91;
|
700 |
-
}
|
701 |
-
// Calc new height
|
702 |
-
var newHeight = Math.round((_newWidth * iheight)/iwidth);
|
703 |
-
$self.width(_newWidth).height(newHeight);
|
704 |
-
});
|
705 |
-
|
706 |
-
});
|
707 |
-
};
|
708 |
-
|
709 |
-
/**
|
710 |
-
* Safely log things if query var is set
|
711 |
-
* @since 1.0.0
|
712 |
-
*/
|
713 |
-
cmb.log = function() {
|
714 |
-
if ( l10n.script_debug && console && typeof console.log === 'function' ) {
|
715 |
-
console.log.apply(console, arguments);
|
716 |
-
}
|
717 |
-
};
|
718 |
-
|
719 |
-
cmb.spinner = function( $context, hide ) {
|
720 |
-
if ( hide ) {
|
721 |
-
$('.cmb-spinner', $context ).hide();
|
722 |
-
}
|
723 |
-
else {
|
724 |
-
$('.cmb-spinner', $context ).show();
|
725 |
-
}
|
726 |
-
};
|
727 |
-
|
728 |
-
// function for running our ajax
|
729 |
-
cmb.doAjax = function($obj) {
|
730 |
-
// get typed value
|
731 |
-
var oembed_url = $obj.val();
|
732 |
-
// only proceed if the field contains more than 6 characters
|
733 |
-
if ( oembed_url.length < 6 ) {
|
734 |
-
return;
|
735 |
-
}
|
736 |
-
|
737 |
-
// only proceed if the user has pasted, pressed a number, letter, or whitelisted characters
|
738 |
-
|
739 |
-
// get field id
|
740 |
-
var field_id = $obj.attr('id');
|
741 |
-
// get our inputs $context for pinpointing
|
742 |
-
var $context = $obj.parents('.cmb-repeat-table tr td');
|
743 |
-
$context = $context.length ? $context : $obj.parents('.cmb_metabox tr td');
|
744 |
-
|
745 |
-
var embed_container = $('.embed_status', $context);
|
746 |
-
var oembed_width = $obj.width();
|
747 |
-
var child_el = $(':first-child', embed_container);
|
748 |
-
|
749 |
-
// http://www.youtube.com/watch?v=dGG7aru2S6U
|
750 |
-
cmb.log( 'oembed_url', oembed_url, field_id );
|
751 |
-
oembed_width = ( embed_container.length && child_el.length ) ? child_el.width() : $obj.width();
|
752 |
-
|
753 |
-
// show our spinner
|
754 |
-
cmb.spinner( $context );
|
755 |
-
// clear out previous results
|
756 |
-
$('.embed_wrap', $context).html('');
|
757 |
-
// and run our ajax function
|
758 |
-
setTimeout( function() {
|
759 |
-
// if they haven't typed in 500 ms
|
760 |
-
if ( $('.cmb_oembed:focus').val() !== oembed_url ) {
|
761 |
-
return;
|
762 |
-
}
|
763 |
-
$.ajax({
|
764 |
-
type : 'post',
|
765 |
-
dataType : 'json',
|
766 |
-
url : l10n.ajaxurl,
|
767 |
-
data : {
|
768 |
-
'action': 'cmb_oembed_handler',
|
769 |
-
'oembed_url': oembed_url,
|
770 |
-
'oembed_width': oembed_width > 300 ? oembed_width : 300,
|
771 |
-
'field_id': field_id,
|
772 |
-
'object_id': $obj.data('objectid'),
|
773 |
-
'object_type': $obj.data('objecttype'),
|
774 |
-
'cmb_ajax_nonce': l10n.ajax_nonce
|
775 |
-
},
|
776 |
-
success: function(response) {
|
777 |
-
cmb.log( response );
|
778 |
-
// Make sure we have a response id
|
779 |
-
if ( typeof response.id === 'undefined' ) {
|
780 |
-
return;
|
781 |
-
}
|
782 |
-
|
783 |
-
// hide our spinner
|
784 |
-
cmb.spinner( $context, true );
|
785 |
-
// and populate our results from ajax response
|
786 |
-
$('.embed_wrap', $context).html(response.result);
|
787 |
-
}
|
788 |
-
});
|
789 |
-
|
790 |
-
}, 500);
|
791 |
-
};
|
792 |
-
|
793 |
-
$(document).ready(cmb.init);
|
794 |
-
|
795 |
-
return cmb;
|
796 |
-
|
797 |
-
})(window, document, jQuery);
|
1 |
+
/**
|
2 |
+
* Controls the behaviours of custom metabox fields.
|
3 |
+
*
|
4 |
+
* @author Andrew Norcross
|
5 |
+
* @author Jared Atchison
|
6 |
+
* @author Bill Erickson
|
7 |
+
* @author Justin Sternberg
|
8 |
+
* @see https://github.com/webdevstudios/Custom-Metaboxes-and-Fields-for-WordPress
|
9 |
+
*/
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Custom jQuery for Custom Metaboxes and Fields
|
13 |
+
*/
|
14 |
+
window.CMB = (function(window, document, $, undefined){
|
15 |
+
'use strict';
|
16 |
+
|
17 |
+
// localization strings
|
18 |
+
var l10n = window.cmb_l10;
|
19 |
+
var setTimeout = window.setTimeout;
|
20 |
+
|
21 |
+
// CMB functionality object
|
22 |
+
var cmb = {
|
23 |
+
formfield : '',
|
24 |
+
idNumber : false,
|
25 |
+
file_frames : {},
|
26 |
+
repeatEls : 'input:not([type="button"]),select,textarea,.cmb_media_status'
|
27 |
+
};
|
28 |
+
|
29 |
+
cmb.metabox = function() {
|
30 |
+
if ( cmb.$metabox ) {
|
31 |
+
return cmb.$metabox;
|
32 |
+
}
|
33 |
+
cmb.$metabox = $('table.cmb_metabox');
|
34 |
+
return cmb.$metabox;
|
35 |
+
};
|
36 |
+
|
37 |
+
cmb.init = function() {
|
38 |
+
|
39 |
+
var $metabox = cmb.metabox();
|
40 |
+
var $repeatGroup = $metabox.find('.repeatable-group');
|
41 |
+
|
42 |
+
// hide our spinner gif if we're on a MP6 dashboard
|
43 |
+
if ( l10n.new_admin_style ) {
|
44 |
+
$metabox.find('.cmb-spinner img').hide();
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Initialize time/date/color pickers
|
49 |
+
*/
|
50 |
+
cmb.initPickers( $metabox.find('input:text.cmb_timepicker'), $metabox.find('input:text.cmb_datepicker'), $metabox.find('input:text.cmb_colorpicker') );
|
51 |
+
|
52 |
+
// Wrap date picker in class to narrow the scope of jQuery UI CSS and prevent conflicts
|
53 |
+
$("#ui-datepicker-div").wrap('<div class="cmb_element" />');
|
54 |
+
|
55 |
+
// Insert toggle button into DOM wherever there is multicheck. credit: Genesis Framework
|
56 |
+
$( '<p><span class="button cmb-multicheck-toggle">' + l10n.check_toggle + '</span></p>' ).insertBefore( 'ul.cmb_checkbox_list' );
|
57 |
+
|
58 |
+
$metabox
|
59 |
+
.on( 'change', '.cmb_upload_file', function() {
|
60 |
+
cmb.formfield = $(this).attr('id');
|
61 |
+
$('#' + cmb.formfield + '_id').val('');
|
62 |
+
})
|
63 |
+
// Media/file management
|
64 |
+
.on( 'click', '.cmb-multicheck-toggle', cmb.toggleCheckBoxes )
|
65 |
+
.on( 'click', '.cmb_upload_button', cmb.handleMedia )
|
66 |
+
.on( 'click', '.cmb_remove_file_button', cmb.handleRemoveMedia )
|
67 |
+
// Repeatable content
|
68 |
+
.on( 'click', '.add-group-row', cmb.addGroupRow )
|
69 |
+
.on( 'click', '.add-row-button', cmb.addAjaxRow )
|
70 |
+
.on( 'click', '.remove-group-row', cmb.removeGroupRow )
|
71 |
+
.on( 'click', '.remove-row-button', cmb.removeAjaxRow )
|
72 |
+
// Ajax oEmbed display
|
73 |
+
.on( 'keyup paste focusout', '.cmb_oembed', cmb.maybeOembed )
|
74 |
+
// Reset titles when removing a row
|
75 |
+
.on( 'cmb_remove_row', '.repeatable-group', cmb.resetTitlesAndIterator );
|
76 |
+
|
77 |
+
if ( $repeatGroup.length ) {
|
78 |
+
$repeatGroup
|
79 |
+
.filter('.sortable').each( function() {
|
80 |
+
// Add sorting arrows
|
81 |
+
$(this).find( '.remove-group-row' ).before( '<a class="shift-rows move-up alignleft" href="#">'+ l10n.up_arrow +'</a> <a class="shift-rows move-down alignleft" href="#">'+ l10n.down_arrow +'</a>' );
|
82 |
+
})
|
83 |
+
.on( 'click', '.shift-rows', cmb.shiftRows )
|
84 |
+
.on( 'cmb_add_row', cmb.emptyValue );
|
85 |
+
}
|
86 |
+
|
87 |
+
// on pageload
|
88 |
+
setTimeout( cmb.resizeoEmbeds, 500);
|
89 |
+
// and on window resize
|
90 |
+
$(window).on( 'resize', cmb.resizeoEmbeds );
|
91 |
+
|
92 |
+
};
|
93 |
+
|
94 |
+
cmb.resetTitlesAndIterator = function() {
|
95 |
+
// Loop repeatable group tables
|
96 |
+
$( '.repeatable-group' ).each( function() {
|
97 |
+
var $table = $(this);
|
98 |
+
// Loop repeatable group table rows
|
99 |
+
$table.find( '.repeatable-grouping' ).each( function( rowindex ) {
|
100 |
+
var $row = $(this);
|
101 |
+
// Reset rows iterator
|
102 |
+
$row.data( 'iterator', rowindex );
|
103 |
+
// Reset rows title
|
104 |
+
$row.find( '.cmb-group-title h4' ).text( $table.find( '.add-group-row' ).data( 'grouptitle' ).replace( '{#}', ( rowindex + 1 ) ) );
|
105 |
+
});
|
106 |
+
});
|
107 |
+
};
|
108 |
+
|
109 |
+
cmb.toggleCheckBoxes = function( event ) {
|
110 |
+
event.preventDefault();
|
111 |
+
var $self = $(this);
|
112 |
+
var $multicheck = $self.parents( 'td' ).find( 'input[type=checkbox]' );
|
113 |
+
|
114 |
+
// If the button has already been clicked once...
|
115 |
+
if ( $self.data( 'checked' ) ) {
|
116 |
+
// clear the checkboxes and remove the flag
|
117 |
+
$multicheck.prop( 'checked', false );
|
118 |
+
$self.data( 'checked', false );
|
119 |
+
}
|
120 |
+
// Otherwise mark the checkboxes and add a flag
|
121 |
+
else {
|
122 |
+
$multicheck.prop( 'checked', true );
|
123 |
+
$self.data( 'checked', true );
|
124 |
+
}
|
125 |
+
};
|
126 |
+
|
127 |
+
cmb.handleMedia = function(event) {
|
128 |
+
|
129 |
+
if ( ! wp ) {
|
130 |
+
return;
|
131 |
+
}
|
132 |
+
|
133 |
+
event.preventDefault();
|
134 |
+
|
135 |
+
var $metabox = cmb.metabox();
|
136 |
+
var $self = $(this);
|
137 |
+
cmb.formfield = $self.prev('input').attr('id');
|
138 |
+
var $formfield = $('#'+cmb.formfield);
|
139 |
+
var formName = $formfield.attr('name');
|
140 |
+
var uploadStatus = true;
|
141 |
+
var attachment = true;
|
142 |
+
var isList = $self.hasClass( 'cmb_upload_list' );
|
143 |
+
|
144 |
+
// If this field's media frame already exists, reopen it.
|
145 |
+
if ( cmb.formfield in cmb.file_frames ) {
|
146 |
+
cmb.file_frames[cmb.formfield].open();
|
147 |
+
return;
|
148 |
+
}
|
149 |
+
|
150 |
+
// Create the media frame.
|
151 |
+
cmb.file_frames[cmb.formfield] = wp.media.frames.file_frame = wp.media({
|
152 |
+
title: $metabox.find('label[for=' + cmb.formfield + ']').text(),
|
153 |
+
button: {
|
154 |
+
text: l10n.upload_file
|
155 |
+
},
|
156 |
+
multiple: isList ? true : false
|
157 |
+
});
|
158 |
+
|
159 |
+
var handlers = {
|
160 |
+
list : function( selection ) {
|
161 |
+
// Get all of our selected files
|
162 |
+
attachment = selection.toJSON();
|
163 |
+
|
164 |
+
$formfield.val(attachment.url);
|
165 |
+
$('#'+ cmb.formfield +'_id').val(attachment.id);
|
166 |
+
|
167 |
+
// Setup our fileGroup array
|
168 |
+
var fileGroup = [];
|
169 |
+
|
170 |
+
// Loop through each attachment
|
171 |
+
$( attachment ).each( function() {
|
172 |
+
if ( this.type && this.type === 'image' ) {
|
173 |
+
// image preview
|
174 |
+
uploadStatus = '<li class="img_status">'+
|
175 |
+
'<img width="50" height="50" src="' + this.url + '" class="attachment-50x50" alt="'+ this.filename +'">'+
|
176 |
+
'<p><a href="#" class="cmb_remove_file_button" rel="'+ cmb.formfield +'['+ this.id +']">'+ l10n.remove_image +'</a></p>'+
|
177 |
+
'<input type="hidden" id="filelist-'+ this.id +'" name="'+ formName +'['+ this.id +']" value="' + this.url + '">'+
|
178 |
+
'</li>';
|
179 |
+
|
180 |
+
} else {
|
181 |
+
// Standard generic output if it's not an image.
|
182 |
+
uploadStatus = '<li>'+ l10n.file +' <strong>'+ this.filename +'</strong> (<a href="' + this.url + '" target="_blank" rel="external">'+ l10n.download +'</a> / <a href="#" class="cmb_remove_file_button" rel="'+ cmb.formfield +'['+ this.id +']">'+ l10n.remove_file +'</a>)'+
|
183 |
+
'<input type="hidden" id="filelist-'+ this.id +'" name="'+ formName +'['+ this.id +']" value="' + this.url + '">'+
|
184 |
+
'</li>';
|
185 |
+
|
186 |
+
}
|
187 |
+
|
188 |
+
// Add our file to our fileGroup array
|
189 |
+
fileGroup.push( uploadStatus );
|
190 |
+
});
|
191 |
+
|
192 |
+
// Append each item from our fileGroup array to .cmb_media_status
|
193 |
+
$( fileGroup ).each( function() {
|
194 |
+
$formfield.siblings('.cmb_media_status').slideDown().append(this);
|
195 |
+
});
|
196 |
+
},
|
197 |
+
single : function( selection ) {
|
198 |
+
// Only get one file from the uploader
|
199 |
+
attachment = selection.first().toJSON();
|
200 |
+
|
201 |
+
$formfield.val(attachment.url);
|
202 |
+
$('#'+ cmb.formfield +'_id').val(attachment.id);
|
203 |
+
|
204 |
+
if ( attachment.type && attachment.type === 'image' ) {
|
205 |
+
// image preview
|
206 |
+
uploadStatus = '<div class="img_status"><img style="max-width: 350px; width: 100%; height: auto;" src="' + attachment.url + '" alt="'+ attachment.filename +'" title="'+ attachment.filename +'" /><p><a href="#" class="cmb_remove_file_button" rel="' + cmb.formfield + '">'+ l10n.remove_image +'</a></p></div>';
|
207 |
+
} else {
|
208 |
+
// Standard generic output if it's not an image.
|
209 |
+
uploadStatus = l10n.file +' <strong>'+ attachment.filename +'</strong> (<a href="'+ attachment.url +'" target="_blank" rel="external">'+ l10n.download +'</a> / <a href="#" class="cmb_remove_file_button" rel="'+ cmb.formfield +'">'+ l10n.remove_file +'</a>)';
|
210 |
+
}
|
211 |
+
|
212 |
+
// add/display our output
|
213 |
+
$formfield.siblings('.cmb_media_status').slideDown().html(uploadStatus);
|
214 |
+
}
|
215 |
+
};
|
216 |
+
|
217 |
+
// When an file is selected, run a callback.
|
218 |
+
cmb.file_frames[cmb.formfield].on( 'select', function() {
|
219 |
+
var selection = cmb.file_frames[cmb.formfield].state().get('selection');
|
220 |
+
var type = isList ? 'list' : 'single';
|
221 |
+
handlers[type]( selection );
|
222 |
+
});
|
223 |
+
|
224 |
+
// Finally, open the modal
|
225 |
+
cmb.file_frames[cmb.formfield].open();
|
226 |
+
};
|
227 |
+
|
228 |
+
cmb.handleRemoveMedia = function( event ) {
|
229 |
+
event.preventDefault();
|
230 |
+
var $self = $(this);
|
231 |
+
if ( $self.is( '.attach_list .cmb_remove_file_button' ) ){
|
232 |
+
$self.parents('li').remove();
|
233 |
+
return false;
|
234 |
+
}
|
235 |
+
cmb.formfield = $self.attr('rel');
|
236 |
+
var $container = $self.parents('.img_status');
|
237 |
+
|
238 |
+
cmb.metabox().find('input#' + cmb.formfield).val('');
|
239 |
+
cmb.metabox().find('input#' + cmb.formfield + '_id').val('');
|
240 |
+
if ( ! $container.length ) {
|
241 |
+
$self.parents('.cmb_media_status').html('');
|
242 |
+
} else {
|
243 |
+
$container.html('');
|
244 |
+
}
|
245 |
+
return false;
|
246 |
+
};
|
247 |
+
|
248 |
+
// src: http://www.benalman.com/projects/jquery-replacetext-plugin/
|
249 |
+
$.fn.replaceText = function(b, a, c) {
|
250 |
+
return this.each(function() {
|
251 |
+
var f = this.firstChild, g, e, d = [];
|
252 |
+
if (f) {
|
253 |
+
do {
|
254 |
+
if (f.nodeType === 3) {
|
255 |
+
g = f.nodeValue;
|
256 |
+
e = g.replace(b, a);
|
257 |
+
if (e !== g) {
|
258 |
+
if (!c && /</.test(e)) {
|
259 |
+
$(f).before(e);
|
260 |
+
d.push(f);
|
261 |
+
} else {
|
262 |
+
f.nodeValue = e;
|
263 |
+
}
|
264 |
+
}
|
265 |
+
}
|
266 |
+
} while (f = f.nextSibling);
|
267 |
+
}
|
268 |
+
if ( d.length ) { $(d).remove(); }
|
269 |
+
});
|
270 |
+
};
|
271 |
+
|
272 |
+
$.fn.cleanRow = function( prevNum, group ) {
|
273 |
+
var $self = $(this);
|
274 |
+
var $inputs = $self.find('input:not([type="button"]), select, textarea, label');
|
275 |
+
if ( group ) {
|
276 |
+
// Remove extra ajaxed rows
|
277 |
+
$self.find('.cmb-repeat-table .repeat-row:not(:first-child)').remove();
|
278 |
+
}
|
279 |
+
cmb.$focus = false;
|
280 |
+
cmb.neweditor_id = [];
|
281 |
+
|
282 |
+
$inputs.filter(':checked').removeAttr( 'checked' );
|
283 |
+
$inputs.filter(':selected').removeAttr( 'selected' );
|
284 |
+
|
285 |
+
if ( $self.find('.cmb-group-title') ) {
|
286 |
+
$self.find( '.cmb-group-title h4' ).text( $self.data( 'title' ).replace( '{#}', ( cmb.idNumber + 1 ) ) );
|
287 |
+
}
|
288 |
+
|
289 |
+
$inputs.each( function(){
|
290 |
+
var $newInput = $(this);
|
291 |
+
var isEditor = $newInput.hasClass( 'wp-editor-area' );
|
292 |
+
var oldFor = $newInput.attr( 'for' );
|
293 |
+
// var $next = $newInput.next();
|
294 |
+
var attrs = {};
|
295 |
+
var newID, oldID;
|
296 |
+
if ( oldFor ) {
|
297 |
+
attrs = { 'for' : oldFor.replace( '_'+ prevNum, '_'+ cmb.idNumber ) };
|
298 |
+
} else {
|
299 |
+
var oldName = $newInput.attr( 'name' );
|
300 |
+
// Replace 'name' attribute key
|
301 |
+
var newName = oldName ? oldName.replace( '['+ prevNum +']', '['+ cmb.idNumber +']' ) : '';
|
302 |
+
oldID = $newInput.attr( 'id' );
|
303 |
+
newID = oldID ? oldID.replace( '_'+ prevNum, '_'+ cmb.idNumber ) : '';
|
304 |
+
attrs = {
|
305 |
+
id: newID,
|
306 |
+
name: newName,
|
307 |
+
// value: '',
|
308 |
+
'data-iterator': cmb.idNumber,
|
309 |
+
};
|
310 |
+
}
|
311 |
+
|
312 |
+
$newInput
|
313 |
+
.removeClass( 'hasDatepicker' )
|
314 |
+
.attr( attrs ).val('');
|
315 |
+
|
316 |
+
// wysiwyg field
|
317 |
+
if ( isEditor ) {
|
318 |
+
// Get new wysiwyg ID
|
319 |
+
newID = newID ? oldID.replace( 'zx'+ prevNum, 'zx'+ cmb.idNumber ) : '';
|
320 |
+
// Empty the contents
|
321 |
+
$newInput.html('');
|
322 |
+
// Get wysiwyg field
|
323 |
+
var $wysiwyg = $newInput.parents( '.cmb-type-wysiwyg' );
|
324 |
+
// Remove extra mce divs
|
325 |
+
$wysiwyg.find('.mce-tinymce:not(:first-child)').remove();
|
326 |
+
// Replace id instances
|
327 |
+
var html = $wysiwyg.html().replace( new RegExp( oldID, 'g' ), newID );
|
328 |
+
// Update field html
|
329 |
+
$wysiwyg.html( html );
|
330 |
+
// Save ids for later to re-init tinymce
|
331 |
+
cmb.neweditor_id.push( { 'id': newID, 'old': oldID } );
|
332 |
+
}
|
333 |
+
|
334 |
+
cmb.$focus = cmb.$focus ? cmb.$focus : $newInput;
|
335 |
+
});
|
336 |
+
|
337 |
+
return this;
|
338 |
+
};
|
339 |
+
|
340 |
+
$.fn.newRowHousekeeping = function() {
|
341 |
+
var $row = $(this);
|
342 |
+
var $colorPicker = $row.find( '.wp-picker-container' );
|
343 |
+
var $list = $row.find( '.cmb_media_status' );
|
344 |
+
|
345 |
+
if ( $colorPicker.length ) {
|
346 |
+
// Need to clean-up colorpicker before appending
|
347 |
+
$colorPicker.each( function() {
|
348 |
+
var $td = $(this).parent();
|
349 |
+
$td.html( $td.find( 'input:text.cmb_colorpicker' ).attr('style', '') );
|
350 |
+
});
|
351 |
+
}
|
352 |
+
|
353 |
+
// Need to clean-up colorpicker before appending
|
354 |
+
if ( $list.length ) {
|
355 |
+
$list.empty();
|
356 |
+
}
|
357 |
+
|
358 |
+
return this;
|
359 |
+
};
|
360 |
+
|
361 |
+
cmb.afterRowInsert = function( $row ) {
|
362 |
+
if ( cmb.$focus ) {
|
363 |
+
cmb.$focus.focus();
|
364 |
+
}
|
365 |
+
|
366 |
+
var _prop;
|
367 |
+
|
368 |
+
// Need to re-init wp_editor instances
|
369 |
+
if ( cmb.neweditor_id.length ) {
|
370 |
+
var i;
|
371 |
+
for ( i = cmb.neweditor_id.length - 1; i >= 0; i-- ) {
|
372 |
+
var id = cmb.neweditor_id[i].id;
|
373 |
+
var old = cmb.neweditor_id[i].old;
|
374 |
+
|
375 |
+
if ( typeof( tinyMCEPreInit.mceInit[ id ] ) === 'undefined' ) {
|
376 |
+
var newSettings = jQuery.extend( {}, tinyMCEPreInit.mceInit[ old ] );
|
377 |
+
|
378 |
+
for ( _prop in newSettings ) {
|
379 |
+
if ( 'string' === typeof( newSettings[_prop] ) ) {
|
380 |
+
newSettings[_prop] = newSettings[_prop].replace( new RegExp( old, 'g' ), id );
|
381 |
+
}
|
382 |
+
}
|
383 |
+
tinyMCEPreInit.mceInit[ id ] = newSettings;
|
384 |
+
}
|
385 |
+
if ( typeof( tinyMCEPreInit.qtInit[ id ] ) === 'undefined' ) {
|
386 |
+
var newQTS = jQuery.extend( {}, tinyMCEPreInit.qtInit[ old ] );
|
387 |
+
for ( _prop in newQTS ) {
|
388 |
+
if ( 'string' === typeof( newQTS[_prop] ) ) {
|
389 |
+
newQTS[_prop] = newQTS[_prop].replace( new RegExp( old, 'g' ), id );
|
390 |
+
}
|
391 |
+
}
|
392 |
+
tinyMCEPreInit.qtInit[ id ] = newQTS;
|
393 |
+
}
|
394 |
+
tinyMCE.init({
|
395 |
+
id : tinyMCEPreInit.mceInit[ id ],
|
396 |
+
});
|
397 |
+
|
398 |
+
}
|
399 |
+
}
|
400 |
+
|
401 |
+
// Init pickers from new row
|
402 |
+
cmb.initPickers( $row.find('input:text.cmb_timepicker'), $row.find('input:text.cmb_datepicker'), $row.find('input:text.cmb_colorpicker') );
|
403 |
+
};
|
404 |
+
|
405 |
+
cmb.updateNameAttr = function () {
|
406 |
+
|
407 |
+
var $this = $(this);
|
408 |
+
var name = $this.attr( 'name' ); // get current name
|
409 |
+
|
410 |
+
// No name? bail
|
411 |
+
if ( typeof name === 'undefined' ) {
|
412 |
+
return false;
|
413 |
+
}
|
414 |
+
|
415 |
+
var prevNum = parseInt( $this.parents( '.repeatable-grouping' ).data( 'iterator' ) );
|
416 |
+
var newNum = prevNum - 1; // Subtract 1 to get new iterator number
|
417 |
+
|
418 |
+
// Update field name attributes so data is not orphaned when a row is removed and post is saved
|
419 |
+
var $newName = name.replace( '[' + prevNum + ']', '[' + newNum + ']' );
|
420 |
+
|
421 |
+
// New name with replaced iterator
|
422 |
+
$this.attr( 'name', $newName );
|
423 |
+
|
424 |
+
};
|
425 |
+
|
426 |
+
cmb.emptyValue = function( event, row ) {
|
427 |
+
$('input:not([type="button"]), textarea', row).val('');
|
428 |
+
};
|
429 |
+
|
430 |
+
cmb.addGroupRow = function( event ) {
|
431 |
+
|
432 |
+
event.preventDefault();
|
433 |
+
|
434 |
+
var $self = $(this);
|
435 |
+
var $table = $('#'+ $self.data('selector'));
|
436 |
+
var $oldRow = $table.find('.repeatable-grouping').last();
|
437 |
+
var prevNum = parseInt( $oldRow.data('iterator') );
|
438 |
+
cmb.idNumber = prevNum + 1;
|
439 |
+
var $row = $oldRow.clone();
|
440 |
+
|
441 |
+
$row.data( 'title', $self.data( 'grouptitle' ) ).newRowHousekeeping().cleanRow( prevNum, true );
|
442 |
+
|
443 |
+
// console.log( '$row.html()', $row.html() );
|
444 |
+
var $newRow = $( '<tr class="repeatable-grouping" data-iterator="'+ cmb.idNumber +'">'+ $row.html() +'</tr>' );
|
445 |
+
$oldRow.after( $newRow );
|
446 |
+
// console.log( '$newRow.html()', $row.html() );
|
447 |
+
|
448 |
+
cmb.afterRowInsert( $newRow );
|
449 |
+
|
450 |
+
if ( $table.find('.repeatable-grouping').length <= 1 ) {
|
451 |
+
$table.find('.remove-group-row').prop('disabled', true);
|
452 |
+
} else {
|
453 |
+
$table.find('.remove-group-row').removeAttr( 'disabled' );
|
454 |
+
}
|
455 |
+
|
456 |
+
$table.trigger( 'cmb_add_row', $newRow );
|
457 |
+
};
|
458 |
+
|
459 |
+
cmb.addAjaxRow = function( event ) {
|
460 |
+
|
461 |
+
event.preventDefault();
|
462 |
+
|
463 |
+
var $self = $(this);
|
464 |
+
var tableselector = '#'+ $self.data('selector');
|
465 |
+
var $table = $(tableselector);
|
466 |
+
var $emptyrow = $table.find('.empty-row');
|
467 |
+
var prevNum = parseInt( $emptyrow.find('[data-iterator]').data('iterator') );
|
468 |
+
cmb.idNumber = prevNum + 1;
|
469 |
+
var $row = $emptyrow.clone();
|
470 |
+
|
471 |
+
$row.newRowHousekeeping().cleanRow( prevNum );
|
472 |
+
|
473 |
+
$emptyrow.removeClass('empty-row').addClass('repeat-row');
|
474 |
+
$emptyrow.after( $row );
|
475 |
+
|
476 |
+
cmb.afterRowInsert( $row );
|
477 |
+
$table.trigger( 'cmb_add_row', $row );
|
478 |
+
};
|
479 |
+
|
480 |
+
cmb.removeGroupRow = function( event ) {
|
481 |
+
event.preventDefault();
|
482 |
+
var $self = $(this);
|
483 |
+
var $table = $('#'+ $self.data('selector'));
|
484 |
+
var $parent = $self.parents('.repeatable-grouping');
|
485 |
+
var noRows = $table.find('.repeatable-grouping').length;
|
486 |
+
|
487 |
+
// when a group is removed loop through all next groups and update fields names
|
488 |
+
$parent.nextAll( '.repeatable-grouping' ).find( cmb.repeatEls ).each( cmb.updateNameAttr );
|
489 |
+
|
490 |
+
if ( noRows > 1 ) {
|
491 |
+
$parent.remove();
|
492 |
+
if ( noRows < 3 ) {
|
493 |
+
$table.find('.remove-group-row').prop('disabled', true);
|
494 |
+
} else {
|
495 |
+
$table.find('.remove-group-row').prop('disabled', false);
|
496 |
+
}
|
497 |
+
$table.trigger( 'cmb_remove_row' );
|
498 |
+
}
|
499 |
+
};
|
500 |
+
|
501 |
+
cmb.removeAjaxRow = function( event ) {
|
502 |
+
event.preventDefault();
|
503 |
+
var $self = $(this);
|
504 |
+
var $parent = $self.parents('tr');
|
505 |
+
var $table = $self.parents('.cmb-repeat-table');
|
506 |
+
|
507 |
+
// cmb.log( 'number of tbodys', $table.length );
|
508 |
+
// cmb.log( 'number of trs', $('tr', $table).length );
|
509 |
+
if ( $table.find('tr').length > 1 ) {
|
510 |
+
if ( $parent.hasClass('empty-row') ) {
|
511 |
+
$parent.prev().addClass( 'empty-row' ).removeClass('repeat-row');
|
512 |
+
}
|
513 |
+
$self.parents('.cmb-repeat-table tr').remove();
|
514 |
+
$table.trigger( 'cmb_remove_row' );
|
515 |
+
}
|
516 |
+
};
|
517 |
+
|
518 |
+
cmb.shiftRows = function( event ) {
|
519 |
+
|
520 |
+
event.preventDefault();
|
521 |
+
|
522 |
+
var $self = $(this);
|
523 |
+
var $parent = $self.parents( '.repeatable-grouping' );
|
524 |
+
var $goto = $self.hasClass( 'move-up' ) ? $parent.prev( '.repeatable-grouping' ) : $parent.next( '.repeatable-grouping' );
|
525 |
+
|
526 |
+
if ( ! $goto.length ) {
|
527 |
+
return;
|
528 |
+
}
|
529 |
+
|
530 |
+
var inputVals = [];
|
531 |
+
// Loop this items fields
|
532 |
+
$parent.find( cmb.repeatEls ).each( function() {
|
533 |
+
var $element = $(this);
|
534 |
+
var val;
|
535 |
+
if ( $element.hasClass('cmb_media_status') ) {
|
536 |
+
// special case for image previews
|
537 |
+
val = $element.html();
|
538 |
+
} else if ( 'checkbox' === $element.attr('type') ) {
|
539 |
+
val = $element.is(':checked');
|
540 |
+
cmb.log( 'checked', val );
|
541 |
+
} else if ( 'select' === $element.prop('tagName') ) {
|
542 |
+
val = $element.is(':selected');
|
543 |
+
cmb.log( 'checked', val );
|
544 |
+
} else {
|
545 |
+
val = $element.val();
|
546 |
+
}
|
547 |
+
// Get all the current values per element
|
548 |
+
inputVals.push( { val: val, $: $element } );
|
549 |
+
});
|
550 |
+
// And swap them all
|
551 |
+
$goto.find( cmb.repeatEls ).each( function( index ) {
|
552 |
+
var $element = $(this);
|
553 |
+
var val;
|
554 |
+
|
555 |
+
if ( $element.hasClass('cmb_media_status') ) {
|
556 |
+
// special case for image previews
|
557 |
+
val = $element.html();
|
558 |
+
$element.html( inputVals[ index ]['val'] );
|
559 |
+
inputVals[ index ]['$'].html( val );
|
560 |
+
|
561 |
+
}
|
562 |
+
// handle checkbox swapping
|
563 |
+
else if ( 'checkbox' === $element.attr('type') ) {
|
564 |
+
inputVals[ index ]['$'].prop( 'checked', $element.is(':checked') );
|
565 |
+
$element.prop( 'checked', inputVals[ index ]['val'] );
|
566 |
+
}
|
567 |
+
// handle select swapping
|
568 |
+
else if ( 'select' === $element.prop('tagName') ) {
|
569 |
+
inputVals[ index ]['$'].prop( 'selected', $element.is(':selected') );
|
570 |
+
$element.prop( 'selected', inputVals[ index ]['val'] );
|
571 |
+
}
|
572 |
+
// handle normal input swapping
|
573 |
+
else {
|
574 |
+
inputVals[ index ]['$'].val( $element.val() );
|
575 |
+
$element.val( inputVals[ index ]['val'] );
|
576 |
+
}
|
577 |
+
});
|
578 |
+
};
|
579 |
+
|
580 |
+
/**
|
581 |
+
* @todo make work, always
|
582 |
+
*/
|
583 |
+
cmb.initPickers = function( $timePickers, $datePickers, $colorPickers ) {
|
584 |
+
// Initialize timepicker
|
585 |
+
cmb.initTimePickers( $timePickers );
|
586 |
+
|
587 |
+
// Initialize jQuery UI datepicker
|
588 |
+
cmb.initDatePickers( $datePickers );
|
589 |
+
|
590 |
+
// Initialize color picker
|
591 |
+
cmb.initColorPickers( $colorPickers );
|
592 |
+
};
|
593 |
+
|
594 |
+
cmb.initTimePickers = function( $selector ) {
|
595 |
+
if ( ! $selector.length ) {
|
596 |
+
return;
|
597 |
+
}
|
598 |
+
|
599 |
+
$selector.timePicker({
|
600 |
+
startTime: "00:00",
|
601 |
+
endTime: "23:59",
|
602 |
+
show24Hours: false,
|
603 |
+
separator: ':',
|
604 |
+
step: 30
|
605 |
+
});
|
606 |
+
};
|
607 |
+
|
608 |
+
cmb.initDatePickers = function( $selector ) {
|
609 |
+
if ( ! $selector.length ) {
|
610 |
+
return;
|
611 |
+
}
|
612 |
+
|
613 |
+
$selector.datepicker( "destroy" );
|
614 |
+
$selector.datepicker();
|
615 |
+
};
|
616 |
+
|
617 |
+
cmb.initColorPickers = function( $selector ) {
|
618 |
+
if ( ! $selector.length ) {
|
619 |
+
return;
|
620 |
+
}
|
621 |
+
if (typeof jQuery.wp === 'object' && typeof jQuery.wp.wpColorPicker === 'function') {
|
622 |
+
|
623 |
+
$selector.wpColorPicker();
|
624 |
+
|
625 |
+
} else {
|
626 |
+
$selector.each( function(i) {
|
627 |
+
$(this).after('<div id="picker-' + i + '" style="z-index: 1000; background: #EEE; border: 1px solid #CCC; position: absolute; display: block;"></div>');
|
628 |
+
$('#picker-' + i).hide().farbtastic($(this));
|
629 |
+
})
|
630 |
+
.focus( function() {
|
631 |
+
$(this).next().show();
|
632 |
+
})
|
633 |
+
.blur( function() {
|
634 |
+
$(this).next().hide();
|
635 |
+
});
|
636 |
+
}
|
637 |
+
};
|
638 |
+
|
639 |
+
cmb.maybeOembed = function( evt ) {
|
640 |
+
var $self = $(this);
|
641 |
+
var type = evt.type;
|
642 |
+
|
643 |
+
var m = {
|
644 |
+
focusout : function() {
|
645 |
+
setTimeout( function() {
|
646 |
+
// if it's been 2 seconds, hide our spinner
|
647 |
+
cmb.spinner( '.postbox table.cmb_metabox', true );
|
648 |
+
}, 2000);
|
649 |
+
},
|
650 |
+
keyup : function() {
|
651 |
+
var betw = function( min, max ) {
|
652 |
+
return ( evt.which <= max && evt.which >= min );
|
653 |
+
};
|
654 |
+
// Only Ajax on normal keystrokes
|
655 |
+
if ( betw( 48, 90 ) || betw( 96, 111 ) || betw( 8, 9 ) || evt.which === 187 || evt.which === 190 ) {
|
656 |
+
// fire our ajax function
|
657 |
+
cmb.doAjax( $self, evt);
|
658 |
+
}
|
659 |
+
},
|
660 |
+
paste : function() {
|
661 |
+
// paste event is fired before the value is filled, so wait a bit
|
662 |
+
setTimeout( function() { cmb.doAjax( $self ); }, 100);
|
663 |
+
}
|
664 |
+
};
|
665 |
+
m[type]();
|
666 |
+
|
667 |
+
};
|
668 |
+
|
669 |
+
/**
|
670 |
+
* Resize oEmbed videos to fit in their respective metaboxes
|
671 |
+
*/
|
672 |
+
cmb.resizeoEmbeds = function() {
|
673 |
+
cmb.metabox().each( function() {
|
674 |
+
var $self = $(this);
|
675 |
+
var $tableWrap = $self.parents('.inside');
|
676 |
+
if ( ! $tableWrap.length ) {
|
677 |
+
return true; // continue
|
678 |
+
}
|
679 |
+
|
680 |
+
// Calculate new width
|
681 |
+
var newWidth = Math.round(($tableWrap.width() * 0.82)*0.97) - 30;
|
682 |
+
if ( newWidth > 639 ) {
|
683 |
+
return true; // continue
|
684 |
+
}
|
685 |
+
|
686 |
+
var $embeds = $self.find('.cmb-type-oembed .embed_status');
|
687 |
+
var $children = $embeds.children().not('.cmb_remove_wrapper');
|
688 |
+
if ( ! $children.length ) {
|
689 |
+
return true; // continue
|
690 |
+
}
|
691 |
+
|
692 |
+
$children.each( function() {
|
693 |
+
var $self = $(this);
|
694 |
+
var iwidth = $self.width();
|
695 |
+
var iheight = $self.height();
|
696 |
+
var _newWidth = newWidth;
|
697 |
+
if ( $self.parents( '.repeat-row' ).length ) {
|
698 |
+
// Make room for our repeatable "remove" button column
|
699 |
+
_newWidth = newWidth - 91;
|
700 |
+
}
|
701 |
+
// Calc new height
|
702 |
+
var newHeight = Math.round((_newWidth * iheight)/iwidth);
|
703 |
+
$self.width(_newWidth).height(newHeight);
|
704 |
+
});
|
705 |
+
|
706 |
+
});
|
707 |
+
};
|
708 |
+
|
709 |
+
/**
|
710 |
+
* Safely log things if query var is set
|
711 |
+
* @since 1.0.0
|
712 |
+
*/
|
713 |
+
cmb.log = function() {
|
714 |
+
if ( l10n.script_debug && console && typeof console.log === 'function' ) {
|
715 |
+
console.log.apply(console, arguments);
|
716 |
+
}
|
717 |
+
};
|
718 |
+
|
719 |
+
cmb.spinner = function( $context, hide ) {
|
720 |
+
if ( hide ) {
|
721 |
+
$('.cmb-spinner', $context ).hide();
|
722 |
+
}
|
723 |
+
else {
|
724 |
+
$('.cmb-spinner', $context ).show();
|
725 |
+
}
|
726 |
+
};
|
727 |
+
|
728 |
+
// function for running our ajax
|
729 |
+
cmb.doAjax = function($obj) {
|
730 |
+
// get typed value
|
731 |
+
var oembed_url = $obj.val();
|
732 |
+
// only proceed if the field contains more than 6 characters
|
733 |
+
if ( oembed_url.length < 6 ) {
|
734 |
+
return;
|
735 |
+
}
|
736 |
+
|
737 |
+
// only proceed if the user has pasted, pressed a number, letter, or whitelisted characters
|
738 |
+
|
739 |
+
// get field id
|
740 |
+
var field_id = $obj.attr('id');
|
741 |
+
// get our inputs $context for pinpointing
|
742 |
+
var $context = $obj.parents('.cmb-repeat-table tr td');
|
743 |
+
$context = $context.length ? $context : $obj.parents('.cmb_metabox tr td');
|
744 |
+
|
745 |
+
var embed_container = $('.embed_status', $context);
|
746 |
+
var oembed_width = $obj.width();
|
747 |
+
var child_el = $(':first-child', embed_container);
|
748 |
+
|
749 |
+
// http://www.youtube.com/watch?v=dGG7aru2S6U
|
750 |
+
cmb.log( 'oembed_url', oembed_url, field_id );
|
751 |
+
oembed_width = ( embed_container.length && child_el.length ) ? child_el.width() : $obj.width();
|
752 |
+
|
753 |
+
// show our spinner
|
754 |
+
cmb.spinner( $context );
|
755 |
+
// clear out previous results
|
756 |
+
$('.embed_wrap', $context).html('');
|
757 |
+
// and run our ajax function
|
758 |
+
setTimeout( function() {
|
759 |
+
// if they haven't typed in 500 ms
|
760 |
+
if ( $('.cmb_oembed:focus').val() !== oembed_url ) {
|
761 |
+
return;
|
762 |
+
}
|
763 |
+
$.ajax({
|
764 |
+
type : 'post',
|
765 |
+
dataType : 'json',
|
766 |
+
url : l10n.ajaxurl,
|
767 |
+
data : {
|
768 |
+
'action': 'cmb_oembed_handler',
|
769 |
+
'oembed_url': oembed_url,
|
770 |
+
'oembed_width': oembed_width > 300 ? oembed_width : 300,
|
771 |
+
'field_id': field_id,
|
772 |
+
'object_id': $obj.data('objectid'),
|
773 |
+
'object_type': $obj.data('objecttype'),
|
774 |
+
'cmb_ajax_nonce': l10n.ajax_nonce
|
775 |
+
},
|
776 |
+
success: function(response) {
|
777 |
+
cmb.log( response );
|
778 |
+
// Make sure we have a response id
|
779 |
+
if ( typeof response.id === 'undefined' ) {
|
780 |
+
return;
|
781 |
+
}
|
782 |
+
|
783 |
+
// hide our spinner
|
784 |
+
cmb.spinner( $context, true );
|
785 |
+
// and populate our results from ajax response
|
786 |
+
$('.embed_wrap', $context).html(response.result);
|
787 |
+
}
|
788 |
+
});
|
789 |
+
|
790 |
+
}, 500);
|
791 |
+
};
|
792 |
+
|
793 |
+
$(document).ready(cmb.init);
|
794 |
+
|
795 |
+
return cmb;
|
796 |
+
|
797 |
+
})(window, document, jQuery);
|
lib/cmb_metaboxes/js/jquery.datePicker.min.js
CHANGED
@@ -1,2038 +1,2038 @@
|
|
1 |
-
/*!
|
2 |
-
* jQuery UI Datepicker 1.10.4
|
3 |
-
* http://jqueryui.com
|
4 |
-
*
|
5 |
-
* Copyright 2014 jQuery Foundation and other contributors
|
6 |
-
* Released under the MIT license.
|
7 |
-
* http://jquery.org/license
|
8 |
-
*
|
9 |
-
* http://api.jqueryui.com/datepicker/
|
10 |
-
*
|
11 |
-
* Depends:
|
12 |
-
* jquery.ui.core.js
|
13 |
-
*/
|
14 |
-
(function( $, undefined ) {
|
15 |
-
|
16 |
-
$.extend($.ui, { datepicker: { version: "1.10.4" } });
|
17 |
-
|
18 |
-
var PROP_NAME = "datepicker",
|
19 |
-
instActive;
|
20 |
-
|
21 |
-
/* Date picker manager.
|
22 |
-
Use the singleton instance of this class, $.datepicker, to interact with the date picker.
|
23 |
-
Settings for (groups of) date pickers are maintained in an instance object,
|
24 |
-
allowing multiple different settings on the same page. */
|
25 |
-
|
26 |
-
function Datepicker() {
|
27 |
-
this._curInst = null; // The current instance in use
|
28 |
-
this._keyEvent = false; // If the last event was a key event
|
29 |
-
this._disabledInputs = []; // List of date picker inputs that have been disabled
|
30 |
-
this._datepickerShowing = false; // True if the popup picker is showing , false if not
|
31 |
-
this._inDialog = false; // True if showing within a "dialog", false if not
|
32 |
-
this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
|
33 |
-
this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
|
34 |
-
this._appendClass = "ui-datepicker-append"; // The name of the append marker class
|
35 |
-
this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
|
36 |
-
this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
|
37 |
-
this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
|
38 |
-
this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
|
39 |
-
this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
|
40 |
-
this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
|
41 |
-
this.regional = []; // Available regional settings, indexed by language code
|
42 |
-
this.regional[""] = { // Default regional settings
|
43 |
-
closeText: "Done", // Display text for close link
|
44 |
-
prevText: "Prev", // Display text for previous month link
|
45 |
-
nextText: "Next", // Display text for next month link
|
46 |
-
currentText: "Today", // Display text for current month link
|
47 |
-
monthNames: ["January","February","March","April","May","June",
|
48 |
-
"July","August","September","October","November","December"], // Names of months for drop-down and formatting
|
49 |
-
monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
|
50 |
-
dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
|
51 |
-
dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
|
52 |
-
dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
|
53 |
-
weekHeader: "Wk", // Column header for week of the year
|
54 |
-
dateFormat: "mm/dd/yy", // See format options on parseDate
|
55 |
-
firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
|
56 |
-
isRTL: false, // True if right-to-left language, false if left-to-right
|
57 |
-
showMonthAfterYear: false, // True if the year select precedes month, false for month then year
|
58 |
-
yearSuffix: "" // Additional text to append to the year in the month headers
|
59 |
-
};
|
60 |
-
this._defaults = { // Global defaults for all the date picker instances
|
61 |
-
showOn: "focus", // "focus" for popup on focus,
|
62 |
-
// "button" for trigger button, or "both" for either
|
63 |
-
showAnim: "fadeIn", // Name of jQuery animation for popup
|
64 |
-
showOptions: {}, // Options for enhanced animations
|
65 |
-
defaultDate: null, // Used when field is blank: actual date,
|
66 |
-
// +/-number for offset from today, null for today
|
67 |
-
appendText: "", // Display text following the input box, e.g. showing the format
|
68 |
-
buttonText: "...", // Text for trigger button
|
69 |
-
buttonImage: "", // URL for trigger button image
|
70 |
-
buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
|
71 |
-
hideIfNoPrevNext: false, // True to hide next/previous month links
|
72 |
-
// if not applicable, false to just disable them
|
73 |
-
navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
|
74 |
-
gotoCurrent: false, // True if today link goes back to current selection instead
|
75 |
-
changeMonth: false, // True if month can be selected directly, false if only prev/next
|
76 |
-
changeYear: false, // True if year can be selected directly, false if only prev/next
|
77 |
-
yearRange: "c-10:c+10", // Range of years to display in drop-down,
|
78 |
-
// either relative to today's year (-nn:+nn), relative to currently displayed year
|
79 |
-
// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
|
80 |
-
showOtherMonths: false, // True to show dates in other months, false to leave blank
|
81 |
-
selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
|
82 |
-
showWeek: false, // True to show week of the year, false to not show it
|
83 |
-
calculateWeek: this.iso8601Week, // How to calculate the week of the year,
|
84 |
-
// takes a Date and returns the number of the week for it
|
85 |
-
shortYearCutoff: "+10", // Short year values < this are in the current century,
|
86 |
-
// > this are in the previous century,
|
87 |
-
// string value starting with "+" for current year + value
|
88 |
-
minDate: null, // The earliest selectable date, or null for no limit
|
89 |
-
maxDate: null, // The latest selectable date, or null for no limit
|
90 |
-
duration: "fast", // Duration of display/closure
|
91 |
-
beforeShowDay: null, // Function that takes a date and returns an array with
|
92 |
-
// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
|
93 |
-
// [2] = cell title (optional), e.g. $.datepicker.noWeekends
|
94 |
-
beforeShow: null, // Function that takes an input field and
|
95 |
-
// returns a set of custom settings for the date picker
|
96 |
-
onSelect: null, // Define a callback function when a date is selected
|
97 |
-
onChangeMonthYear: null, // Define a callback function when the month or year is changed
|
98 |
-
onClose: null, // Define a callback function when the datepicker is closed
|
99 |
-
numberOfMonths: 1, // Number of months to show at a time
|
100 |
-
showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
|
101 |
-
stepMonths: 1, // Number of months to step back/forward
|
102 |
-
stepBigMonths: 12, // Number of months to step back/forward for the big links
|
103 |
-
altField: "", // Selector for an alternate field to store selected dates into
|
104 |
-
altFormat: "", // The date format to use for the alternate field
|
105 |
-
constrainInput: true, // The input is constrained by the current date format
|
106 |
-
showButtonPanel: false, // True to show button panel, false to not show it
|
107 |
-
autoSize: false, // True to size the input for the date format, false to leave as is
|
108 |
-
disabled: false // The initial disabled state
|
109 |
-
};
|
110 |
-
$.extend(this._defaults, this.regional[""]);
|
111 |
-
this.dpDiv = bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
|
112 |
-
}
|
113 |
-
|
114 |
-
$.extend(Datepicker.prototype, {
|
115 |
-
/* Class name added to elements to indicate already configured with a date picker. */
|
116 |
-
markerClassName: "hasDatepicker",
|
117 |
-
|
118 |
-
//Keep track of the maximum number of rows displayed (see #7043)
|
119 |
-
maxRows: 4,
|
120 |
-
|
121 |
-
// TODO rename to "widget" when switching to widget factory
|
122 |
-
_widgetDatepicker: function() {
|
123 |
-
return this.dpDiv;
|
124 |
-
},
|
125 |
-
|
126 |
-
/* Override the default settings for all instances of the date picker.
|
127 |
-
* @param settings object - the new settings to use as defaults (anonymous object)
|
128 |
-
* @return the manager object
|
129 |
-
*/
|
130 |
-
setDefaults: function(settings) {
|
131 |
-
extendRemove(this._defaults, settings || {});
|
132 |
-
return this;
|
133 |
-
},
|
134 |
-
|
135 |
-
/* Attach the date picker to a jQuery selection.
|
136 |
-
* @param target element - the target input field or division or span
|
137 |
-
* @param settings object - the new settings to use for this date picker instance (anonymous)
|
138 |
-
*/
|
139 |
-
_attachDatepicker: function(target, settings) {
|
140 |
-
var nodeName, inline, inst;
|
141 |
-
nodeName = target.nodeName.toLowerCase();
|
142 |
-
inline = (nodeName === "div" || nodeName === "span");
|
143 |
-
if (!target.id) {
|
144 |
-
this.uuid += 1;
|
145 |
-
target.id = "dp" + this.uuid;
|
146 |
-
}
|
147 |
-
inst = this._newInst($(target), inline);
|
148 |
-
inst.settings = $.extend({}, settings || {});
|
149 |
-
if (nodeName === "input") {
|
150 |
-
this._connectDatepicker(target, inst);
|
151 |
-
} else if (inline) {
|
152 |
-
this._inlineDatepicker(target, inst);
|
153 |
-
}
|
154 |
-
},
|
155 |
-
|
156 |
-
/* Create a new instance object. */
|
157 |
-
_newInst: function(target, inline) {
|
158 |
-
var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
|
159 |
-
return {id: id, input: target, // associated target
|
160 |
-
selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
|
161 |
-
drawMonth: 0, drawYear: 0, // month being drawn
|
162 |
-
inline: inline, // is datepicker inline or not
|
163 |
-
dpDiv: (!inline ? this.dpDiv : // presentation div
|
164 |
-
bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
|
165 |
-
},
|
166 |
-
|
167 |
-
/* Attach the date picker to an input field. */
|
168 |
-
_connectDatepicker: function(target, inst) {
|
169 |
-
var input = $(target);
|
170 |
-
inst.append = $([]);
|
171 |
-
inst.trigger = $([]);
|
172 |
-
if (input.hasClass(this.markerClassName)) {
|
173 |
-
return;
|
174 |
-
}
|
175 |
-
this._attachments(input, inst);
|
176 |
-
input.addClass(this.markerClassName).keydown(this._doKeyDown).
|
177 |
-
keypress(this._doKeyPress).keyup(this._doKeyUp);
|
178 |
-
this._autoSize(inst);
|
179 |
-
$.data(target, PROP_NAME, inst);
|
180 |
-
//If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
|
181 |
-
if( inst.settings.disabled ) {
|
182 |
-
this._disableDatepicker( target );
|
183 |
-
}
|
184 |
-
},
|
185 |
-
|
186 |
-
/* Make attachments based on settings. */
|
187 |
-
_attachments: function(input, inst) {
|
188 |
-
var showOn, buttonText, buttonImage,
|
189 |
-
appendText = this._get(inst, "appendText"),
|
190 |
-
isRTL = this._get(inst, "isRTL");
|
191 |
-
|
192 |
-
if (inst.append) {
|
193 |
-
inst.append.remove();
|
194 |
-
}
|
195 |
-
if (appendText) {
|
196 |
-
inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
|
197 |
-
input[isRTL ? "before" : "after"](inst.append);
|
198 |
-
}
|
199 |
-
|
200 |
-
input.unbind("focus", this._showDatepicker);
|
201 |
-
|
202 |
-
if (inst.trigger) {
|
203 |
-
inst.trigger.remove();
|
204 |
-
}
|
205 |
-
|
206 |
-
showOn = this._get(inst, "showOn");
|
207 |
-
if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
|
208 |
-
input.focus(this._showDatepicker);
|
209 |
-
}
|
210 |
-
if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
|
211 |
-
buttonText = this._get(inst, "buttonText");
|
212 |
-
buttonImage = this._get(inst, "buttonImage");
|
213 |
-
inst.trigger = $(this._get(inst, "buttonImageOnly") ?
|
214 |
-
$("<img/>").addClass(this._triggerClass).
|
215 |
-
attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
|
216 |
-
$("<button type='button'></button>").addClass(this._triggerClass).
|
217 |
-
html(!buttonImage ? buttonText : $("<img/>").attr(
|
218 |
-
{ src:buttonImage, alt:buttonText, title:buttonText })));
|
219 |
-
input[isRTL ? "before" : "after"](inst.trigger);
|
220 |
-
inst.trigger.click(function() {
|
221 |
-
if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
|
222 |
-
$.datepicker._hideDatepicker();
|
223 |
-
} else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
|
224 |
-
$.datepicker._hideDatepicker();
|
225 |
-
$.datepicker._showDatepicker(input[0]);
|
226 |
-
} else {
|
227 |
-
$.datepicker._showDatepicker(input[0]);
|
228 |
-
}
|
229 |
-
return false;
|
230 |
-
});
|
231 |
-
}
|
232 |
-
},
|
233 |
-
|
234 |
-
/* Apply the maximum length for the date format. */
|
235 |
-
_autoSize: function(inst) {
|
236 |
-
if (this._get(inst, "autoSize") && !inst.inline) {
|
237 |
-
var findMax, max, maxI, i,
|
238 |
-
date = new Date(2009, 12 - 1, 20), // Ensure double digits
|
239 |
-
dateFormat = this._get(inst, "dateFormat");
|
240 |
-
|
241 |
-
if (dateFormat.match(/[DM]/)) {
|
242 |
-
findMax = function(names) {
|
243 |
-
max = 0;
|
244 |
-
maxI = 0;
|
245 |
-
for (i = 0; i < names.length; i++) {
|
246 |
-
if (names[i].length > max) {
|
247 |
-
max = names[i].length;
|
248 |
-
maxI = i;
|
249 |
-
}
|
250 |
-
}
|
251 |
-
return maxI;
|
252 |
-
};
|
253 |
-
date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
|
254 |
-
"monthNames" : "monthNamesShort"))));
|
255 |
-
date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
|
256 |
-
"dayNames" : "dayNamesShort"))) + 20 - date.getDay());
|
257 |
-
}
|
258 |
-
inst.input.attr("size", this._formatDate(inst, date).length);
|
259 |
-
}
|
260 |
-
},
|
261 |
-
|
262 |
-
/* Attach an inline date picker to a div. */
|
263 |
-
_inlineDatepicker: function(target, inst) {
|
264 |
-
var divSpan = $(target);
|
265 |
-
if (divSpan.hasClass(this.markerClassName)) {
|
266 |
-
return;
|
267 |
-
}
|
268 |
-
divSpan.addClass(this.markerClassName).append(inst.dpDiv);
|
269 |
-
$.data(target, PROP_NAME, inst);
|
270 |
-
this._setDate(inst, this._getDefaultDate(inst), true);
|
271 |
-
this._updateDatepicker(inst);
|
272 |
-
this._updateAlternate(inst);
|
273 |
-
//If disabled option is true, disable the datepicker before showing it (see ticket #5665)
|
274 |
-
if( inst.settings.disabled ) {
|
275 |
-
this._disableDatepicker( target );
|
276 |
-
}
|
277 |
-
// Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
|
278 |
-
// http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
|
279 |
-
inst.dpDiv.css( "display", "block" );
|
280 |
-
},
|
281 |
-
|
282 |
-
/* Pop-up the date picker in a "dialog" box.
|
283 |
-
* @param input element - ignored
|
284 |
-
* @param date string or Date - the initial date to display
|
285 |
-
* @param onSelect function - the function to call when a date is selected
|
286 |
-
* @param settings object - update the dialog date picker instance's settings (anonymous object)
|
287 |
-
* @param pos int[2] - coordinates for the dialog's position within the screen or
|
288 |
-
* event - with x/y coordinates or
|
289 |
-
* leave empty for default (screen centre)
|
290 |
-
* @return the manager object
|
291 |
-
*/
|
292 |
-
_dialogDatepicker: function(input, date, onSelect, settings, pos) {
|
293 |
-
var id, browserWidth, browserHeight, scrollX, scrollY,
|
294 |
-
inst = this._dialogInst; // internal instance
|
295 |
-
|
296 |
-
if (!inst) {
|
297 |
-
this.uuid += 1;
|
298 |
-
id = "dp" + this.uuid;
|
299 |
-
this._dialogInput = $("<input type='text' id='" + id +
|
300 |
-
"' style='position: absolute; top: -100px; width: 0px;'/>");
|
301 |
-
this._dialogInput.keydown(this._doKeyDown);
|
302 |
-
$("body").append(this._dialogInput);
|
303 |
-
inst = this._dialogInst = this._newInst(this._dialogInput, false);
|
304 |
-
inst.settings = {};
|
305 |
-
$.data(this._dialogInput[0], PROP_NAME, inst);
|
306 |
-
}
|
307 |
-
extendRemove(inst.settings, settings || {});
|
308 |
-
date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
|
309 |
-
this._dialogInput.val(date);
|
310 |
-
|
311 |
-
this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
|
312 |
-
if (!this._pos) {
|
313 |
-
browserWidth = document.documentElement.clientWidth;
|
314 |
-
browserHeight = document.documentElement.clientHeight;
|
315 |
-
scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
|
316 |
-
scrollY = document.documentElement.scrollTop || document.body.scrollTop;
|
317 |
-
this._pos = // should use actual width/height below
|
318 |
-
[(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
|
319 |
-
}
|
320 |
-
|
321 |
-
// move input on screen for focus, but hidden behind dialog
|
322 |
-
this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
|
323 |
-
inst.settings.onSelect = onSelect;
|
324 |
-
this._inDialog = true;
|
325 |
-
this.dpDiv.addClass(this._dialogClass);
|
326 |
-
this._showDatepicker(this._dialogInput[0]);
|
327 |
-
if ($.blockUI) {
|
328 |
-
$.blockUI(this.dpDiv);
|
329 |
-
}
|
330 |
-
$.data(this._dialogInput[0], PROP_NAME, inst);
|
331 |
-
return this;
|
332 |
-
},
|
333 |
-
|
334 |
-
/* Detach a datepicker from its control.
|
335 |
-
* @param target element - the target input field or division or span
|
336 |
-
*/
|
337 |
-
_destroyDatepicker: function(target) {
|
338 |
-
var nodeName,
|
339 |
-
$target = $(target),
|
340 |
-
inst = $.data(target, PROP_NAME);
|
341 |
-
|
342 |
-
if (!$target.hasClass(this.markerClassName)) {
|
343 |
-
return;
|
344 |
-
}
|
345 |
-
|
346 |
-
nodeName = target.nodeName.toLowerCase();
|
347 |
-
$.removeData(target, PROP_NAME);
|
348 |
-
if (nodeName === "input") {
|
349 |
-
inst.append.remove();
|
350 |
-
inst.trigger.remove();
|
351 |
-
$target.removeClass(this.markerClassName).
|
352 |
-
unbind("focus", this._showDatepicker).
|
353 |
-
unbind("keydown", this._doKeyDown).
|
354 |
-
unbind("keypress", this._doKeyPress).
|
355 |
-
unbind("keyup", this._doKeyUp);
|
356 |
-
} else if (nodeName === "div" || nodeName === "span") {
|
357 |
-
$target.removeClass(this.markerClassName).empty();
|
358 |
-
}
|
359 |
-
},
|
360 |
-
|
361 |
-
/* Enable the date picker to a jQuery selection.
|
362 |
-
* @param target element - the target input field or division or span
|
363 |
-
*/
|
364 |
-
_enableDatepicker: function(target) {
|
365 |
-
var nodeName, inline,
|
366 |
-
$target = $(target),
|
367 |
-
inst = $.data(target, PROP_NAME);
|
368 |
-
|
369 |
-
if (!$target.hasClass(this.markerClassName)) {
|
370 |
-
return;
|
371 |
-
}
|
372 |
-
|
373 |
-
nodeName = target.nodeName.toLowerCase();
|
374 |
-
if (nodeName === "input") {
|
375 |
-
target.disabled = false;
|
376 |
-
inst.trigger.filter("button").
|
377 |
-
each(function() { this.disabled = false; }).end().
|
378 |
-
filter("img").css({opacity: "1.0", cursor: ""});
|
379 |
-
} else if (nodeName === "div" || nodeName === "span") {
|
380 |
-
inline = $target.children("." + this._inlineClass);
|
381 |
-
inline.children().removeClass("ui-state-disabled");
|
382 |
-
inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
|
383 |
-
prop("disabled", false);
|
384 |
-
}
|
385 |
-
this._disabledInputs = $.map(this._disabledInputs,
|
386 |
-
function(value) { return (value === target ? null : value); }); // delete entry
|
387 |
-
},
|
388 |
-
|
389 |
-
/* Disable the date picker to a jQuery selection.
|
390 |
-
* @param target element - the target input field or division or span
|
391 |
-
*/
|
392 |
-
_disableDatepicker: function(target) {
|
393 |
-
var nodeName, inline,
|
394 |
-
$target = $(target),
|
395 |
-
inst = $.data(target, PROP_NAME);
|
396 |
-
|
397 |
-
if (!$target.hasClass(this.markerClassName)) {
|
398 |
-
return;
|
399 |
-
}
|
400 |
-
|
401 |
-
nodeName = target.nodeName.toLowerCase();
|
402 |
-
if (nodeName === "input") {
|
403 |
-
target.disabled = true;
|
404 |
-
inst.trigger.filter("button").
|
405 |
-
each(function() { this.disabled = true; }).end().
|
406 |
-
filter("img").css({opacity: "0.5", cursor: "default"});
|
407 |
-
} else if (nodeName === "div" || nodeName === "span") {
|
408 |
-
inline = $target.children("." + this._inlineClass);
|
409 |
-
inline.children().addClass("ui-state-disabled");
|
410 |
-
inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
|
411 |
-
prop("disabled", true);
|
412 |
-
}
|
413 |
-
this._disabledInputs = $.map(this._disabledInputs,
|
414 |
-
function(value) { return (value === target ? null : value); }); // delete entry
|
415 |
-
this._disabledInputs[this._disabledInputs.length] = target;
|
416 |
-
},
|
417 |
-
|
418 |
-
/* Is the first field in a jQuery collection disabled as a datepicker?
|
419 |
-
* @param target element - the target input field or division or span
|
420 |
-
* @return boolean - true if disabled, false if enabled
|
421 |
-
*/
|
422 |
-
_isDisabledDatepicker: function(target) {
|
423 |
-
if (!target) {
|
424 |
-
return false;
|
425 |
-
}
|
426 |
-
for (var i = 0; i < this._disabledInputs.length; i++) {
|
427 |
-
if (this._disabledInputs[i] === target) {
|
428 |
-
return true;
|
429 |
-
}
|
430 |
-
}
|
431 |
-
return false;
|
432 |
-
},
|
433 |
-
|
434 |
-
/* Retrieve the instance data for the target control.
|
435 |
-
* @param target element - the target input field or division or span
|
436 |
-
* @return object - the associated instance data
|
437 |
-
* @throws error if a jQuery problem getting data
|
438 |
-
*/
|
439 |
-
_getInst: function(target) {
|
440 |
-
try {
|
441 |
-
return $.data(target, PROP_NAME);
|
442 |
-
}
|
443 |
-
catch (err) {
|
444 |
-
throw "Missing instance data for this datepicker";
|
445 |
-
}
|
446 |
-
},
|
447 |
-
|
448 |
-
/* Update or retrieve the settings for a date picker attached to an input field or division.
|
449 |
-
* @param target element - the target input field or division or span
|
450 |
-
* @param name object - the new settings to update or
|
451 |
-
* string - the name of the setting to change or retrieve,
|
452 |
-
* when retrieving also "all" for all instance settings or
|
453 |
-
* "defaults" for all global defaults
|
454 |
-
* @param value any - the new value for the setting
|
455 |
-
* (omit if above is an object or to retrieve a value)
|
456 |
-
*/
|
457 |
-
_optionDatepicker: function(target, name, value) {
|
458 |
-
var settings, date, minDate, maxDate,
|
459 |
-
inst = this._getInst(target);
|
460 |
-
|
461 |
-
if (arguments.length === 2 && typeof name === "string") {
|
462 |
-
return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
|
463 |
-
(inst ? (name === "all" ? $.extend({}, inst.settings) :
|
464 |
-
this._get(inst, name)) : null));
|
465 |
-
}
|
466 |
-
|
467 |
-
settings = name || {};
|
468 |
-
if (typeof name === "string") {
|
469 |
-
settings = {};
|
470 |
-
settings[name] = value;
|
471 |
-
}
|
472 |
-
|
473 |
-
if (inst) {
|
474 |
-
if (this._curInst === inst) {
|
475 |
-
this._hideDatepicker();
|
476 |
-
}
|
477 |
-
|
478 |
-
date = this._getDateDatepicker(target, true);
|
479 |
-
minDate = this._getMinMaxDate(inst, "min");
|
480 |
-
maxDate = this._getMinMaxDate(inst, "max");
|
481 |
-
extendRemove(inst.settings, settings);
|
482 |
-
// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
|
483 |
-
if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
|
484 |
-
inst.settings.minDate = this._formatDate(inst, minDate);
|
485 |
-
}
|
486 |
-
if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
|
487 |
-
inst.settings.maxDate = this._formatDate(inst, maxDate);
|
488 |
-
}
|
489 |
-
if ( "disabled" in settings ) {
|
490 |
-
if ( settings.disabled ) {
|
491 |
-
this._disableDatepicker(target);
|
492 |
-
} else {
|
493 |
-
this._enableDatepicker(target);
|
494 |
-
}
|
495 |
-
}
|
496 |
-
this._attachments($(target), inst);
|
497 |
-
this._autoSize(inst);
|
498 |
-
this._setDate(inst, date);
|
499 |
-
this._updateAlternate(inst);
|
500 |
-
this._updateDatepicker(inst);
|
501 |
-
}
|
502 |
-
},
|
503 |
-
|
504 |
-
// change method deprecated
|
505 |
-
_changeDatepicker: function(target, name, value) {
|
506 |
-
this._optionDatepicker(target, name, value);
|
507 |
-
},
|
508 |
-
|
509 |
-
/* Redraw the date picker attached to an input field or division.
|
510 |
-
* @param target element - the target input field or division or span
|
511 |
-
*/
|
512 |
-
_refreshDatepicker: function(target) {
|
513 |
-
var inst = this._getInst(target);
|
514 |
-
if (inst) {
|
515 |
-
this._updateDatepicker(inst);
|
516 |
-
}
|
517 |
-
},
|
518 |
-
|
519 |
-
/* Set the dates for a jQuery selection.
|
520 |
-
* @param target element - the target input field or division or span
|
521 |
-
* @param date Date - the new date
|
522 |
-
*/
|
523 |
-
_setDateDatepicker: function(target, date) {
|
524 |
-
var inst = this._getInst(target);
|
525 |
-
if (inst) {
|
526 |
-
this._setDate(inst, date);
|
527 |
-
this._updateDatepicker(inst);
|
528 |
-
this._updateAlternate(inst);
|
529 |
-
}
|
530 |
-
},
|
531 |
-
|
532 |
-
/* Get the date(s) for the first entry in a jQuery selection.
|
533 |
-
* @param target element - the target input field or division or span
|
534 |
-
* @param noDefault boolean - true if no default date is to be used
|
535 |
-
* @return Date - the current date
|
536 |
-
*/
|
537 |
-
_getDateDatepicker: function(target, noDefault) {
|
538 |
-
var inst = this._getInst(target);
|
539 |
-
if (inst && !inst.inline) {
|
540 |
-
this._setDateFromField(inst, noDefault);
|
541 |
-
}
|
542 |
-
return (inst ? this._getDate(inst) : null);
|
543 |
-
},
|
544 |
-
|
545 |
-
/* Handle keystrokes. */
|
546 |
-
_doKeyDown: function(event) {
|
547 |
-
var onSelect, dateStr, sel,
|
548 |
-
inst = $.datepicker._getInst(event.target),
|
549 |
-
handled = true,
|
550 |
-
isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
|
551 |
-
|
552 |
-
inst._keyEvent = true;
|
553 |
-
if ($.datepicker._datepickerShowing) {
|
554 |
-
switch (event.keyCode) {
|
555 |
-
case 9: $.datepicker._hideDatepicker();
|
556 |
-
handled = false;
|
557 |
-
break; // hide on tab out
|
558 |
-
case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
|
559 |
-
$.datepicker._currentClass + ")", inst.dpDiv);
|
560 |
-
if (sel[0]) {
|
561 |
-
$.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
|
562 |
-
}
|
563 |
-
|
564 |
-
onSelect = $.datepicker._get(inst, "onSelect");
|
565 |
-
if (onSelect) {
|
566 |
-
dateStr = $.datepicker._formatDate(inst);
|
567 |
-
|
568 |
-
// trigger custom callback
|
569 |
-
onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
|
570 |
-
} else {
|
571 |
-
$.datepicker._hideDatepicker();
|
572 |
-
}
|
573 |
-
|
574 |
-
return false; // don't submit the form
|
575 |
-
case 27: $.datepicker._hideDatepicker();
|
576 |
-
break; // hide on escape
|
577 |
-
case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
|
578 |
-
-$.datepicker._get(inst, "stepBigMonths") :
|
579 |
-
-$.datepicker._get(inst, "stepMonths")), "M");
|
580 |
-
break; // previous month/year on page up/+ ctrl
|
581 |
-
case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
|
582 |
-
+$.datepicker._get(inst, "stepBigMonths") :
|
583 |
-
+$.datepicker._get(inst, "stepMonths")), "M");
|
584 |
-
break; // next month/year on page down/+ ctrl
|
585 |
-
case 35: if (event.ctrlKey || event.metaKey) {
|
586 |
-
$.datepicker._clearDate(event.target);
|
587 |
-
}
|
588 |
-
handled = event.ctrlKey || event.metaKey;
|
589 |
-
break; // clear on ctrl or command +end
|
590 |
-
case 36: if (event.ctrlKey || event.metaKey) {
|
591 |
-
$.datepicker._gotoToday(event.target);
|
592 |
-
}
|
593 |
-
handled = event.ctrlKey || event.metaKey;
|
594 |
-
break; // current on ctrl or command +home
|
595 |
-
case 37: if (event.ctrlKey || event.metaKey) {
|
596 |
-
$.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
|
597 |
-
}
|
598 |
-
handled = event.ctrlKey || event.metaKey;
|
599 |
-
// -1 day on ctrl or command +left
|
600 |
-
if (event.originalEvent.altKey) {
|
601 |
-
$.datepicker._adjustDate(event.target, (event.ctrlKey ?
|
602 |
-
-$.datepicker._get(inst, "stepBigMonths") :
|
603 |
-
-$.datepicker._get(inst, "stepMonths")), "M");
|
604 |
-
}
|
605 |
-
// next month/year on alt +left on Mac
|
606 |
-
break;
|
607 |
-
case 38: if (event.ctrlKey || event.metaKey) {
|
608 |
-
$.datepicker._adjustDate(event.target, -7, "D");
|
609 |
-
}
|
610 |
-
handled = event.ctrlKey || event.metaKey;
|
611 |
-
break; // -1 week on ctrl or command +up
|
612 |
-
case 39: if (event.ctrlKey || event.metaKey) {
|
613 |
-
$.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
|
614 |
-
}
|
615 |
-
handled = event.ctrlKey || event.metaKey;
|
616 |
-
// +1 day on ctrl or command +right
|
617 |
-
if (event.originalEvent.altKey) {
|
618 |
-
$.datepicker._adjustDate(event.target, (event.ctrlKey ?
|
619 |
-
+$.datepicker._get(inst, "stepBigMonths") :
|
620 |
-
+$.datepicker._get(inst, "stepMonths")), "M");
|
621 |
-
}
|
622 |
-
// next month/year on alt +right
|
623 |
-
break;
|
624 |
-
case 40: if (event.ctrlKey || event.metaKey) {
|
625 |
-
$.datepicker._adjustDate(event.target, +7, "D");
|
626 |
-
}
|
627 |
-
handled = event.ctrlKey || event.metaKey;
|
628 |
-
break; // +1 week on ctrl or command +down
|
629 |
-
default: handled = false;
|
630 |
-
}
|
631 |
-
} else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
|
632 |
-
$.datepicker._showDatepicker(this);
|
633 |
-
} else {
|
634 |
-
handled = false;
|
635 |
-
}
|
636 |
-
|
637 |
-
if (handled) {
|
638 |
-
event.preventDefault();
|
639 |
-
event.stopPropagation();
|
640 |
-
}
|
641 |
-
},
|
642 |
-
|
643 |
-
/* Filter entered characters - based on date format. */
|
644 |
-
_doKeyPress: function(event) {
|
645 |
-
var chars, chr,
|
646 |
-
inst = $.datepicker._getInst(event.target);
|
647 |
-
|
648 |
-
if ($.datepicker._get(inst, "constrainInput")) {
|
649 |
-
chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
|
650 |
-
chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
|
651 |
-
return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
|
652 |
-
}
|
653 |
-
},
|
654 |
-
|
655 |
-
/* Synchronise manual entry and field/alternate field. */
|
656 |
-
_doKeyUp: function(event) {
|
657 |
-
var date,
|
658 |
-
inst = $.datepicker._getInst(event.target);
|
659 |
-
|
660 |
-
if (inst.input.val() !== inst.lastVal) {
|
661 |
-
try {
|
662 |
-
date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
|
663 |
-
(inst.input ? inst.input.val() : null),
|
664 |
-
$.datepicker._getFormatConfig(inst));
|
665 |
-
|
666 |
-
if (date) { // only if valid
|
667 |
-
$.datepicker._setDateFromField(inst);
|
668 |
-
$.datepicker._updateAlternate(inst);
|
669 |
-
$.datepicker._updateDatepicker(inst);
|
670 |
-
}
|
671 |
-
}
|
672 |
-
catch (err) {
|
673 |
-
}
|
674 |
-
}
|
675 |
-
return true;
|
676 |
-
},
|
677 |
-
|
678 |
-
/* Pop-up the date picker for a given input field.
|
679 |
-
* If false returned from beforeShow event handler do not show.
|
680 |
-
* @param input element - the input field attached to the date picker or
|
681 |
-
* event - if triggered by focus
|
682 |
-
*/
|
683 |
-
_showDatepicker: function(input) {
|
684 |
-
input = input.target || input;
|
685 |
-
if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
|
686 |
-
input = $("input", input.parentNode)[0];
|
687 |
-
}
|
688 |
-
|
689 |
-
if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
|
690 |
-
return;
|
691 |
-
}
|
692 |
-
|
693 |
-
var inst, beforeShow, beforeShowSettings, isFixed,
|
694 |
-
offset, showAnim, duration;
|
695 |
-
|
696 |
-
inst = $.datepicker._getInst(input);
|
697 |
-
if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
|
698 |
-
$.datepicker._curInst.dpDiv.stop(true, true);
|
699 |
-
if ( inst && $.datepicker._datepickerShowing ) {
|
700 |
-
$.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
|
701 |
-
}
|
702 |
-
}
|
703 |
-
|
704 |
-
beforeShow = $.datepicker._get(inst, "beforeShow");
|
705 |
-
beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
|
706 |
-
if(beforeShowSettings === false){
|
707 |
-
return;
|
708 |
-
}
|
709 |
-
extendRemove(inst.settings, beforeShowSettings);
|
710 |
-
|
711 |
-
inst.lastVal = null;
|
712 |
-
$.datepicker._lastInput = input;
|
713 |
-
$.datepicker._setDateFromField(inst);
|
714 |
-
|
715 |
-
if ($.datepicker._inDialog) { // hide cursor
|
716 |
-
input.value = "";
|
717 |
-
}
|
718 |
-
if (!$.datepicker._pos) { // position below input
|
719 |
-
$.datepicker._pos = $.datepicker._findPos(input);
|
720 |
-
$.datepicker._pos[1] += input.offsetHeight; // add the height
|
721 |
-
}
|
722 |
-
|
723 |
-
isFixed = false;
|
724 |
-
$(input).parents().each(function() {
|
725 |
-
isFixed |= $(this).css("position") === "fixed";
|
726 |
-
return !isFixed;
|
727 |
-
});
|
728 |
-
|
729 |
-
offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
|
730 |
-
$.datepicker._pos = null;
|
731 |
-
//to avoid flashes on Firefox
|
732 |
-
inst.dpDiv.empty();
|
733 |
-
// determine sizing offscreen
|
734 |
-
inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
|
735 |
-
$.datepicker._updateDatepicker(inst);
|
736 |
-
// fix width for dynamic number of date pickers
|
737 |
-
// and adjust position before showing
|
738 |
-
offset = $.datepicker._checkOffset(inst, offset, isFixed);
|
739 |
-
inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
|
740 |
-
"static" : (isFixed ? "fixed" : "absolute")), display: "none",
|
741 |
-
left: offset.left + "px", top: offset.top + "px"});
|
742 |
-
|
743 |
-
if (!inst.inline) {
|
744 |
-
showAnim = $.datepicker._get(inst, "showAnim");
|
745 |
-
duration = $.datepicker._get(inst, "duration");
|
746 |
-
inst.dpDiv.zIndex($(input).zIndex()+1);
|
747 |
-
$.datepicker._datepickerShowing = true;
|
748 |
-
|
749 |
-
if ( $.effects && $.effects.effect[ showAnim ] ) {
|
750 |
-
inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
|
751 |
-
} else {
|
752 |
-
inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
|
753 |
-
}
|
754 |
-
|
755 |
-
if ( $.datepicker._shouldFocusInput( inst ) ) {
|
756 |
-
inst.input.focus();
|
757 |
-
}
|
758 |
-
|
759 |
-
$.datepicker._curInst = inst;
|
760 |
-
}
|
761 |
-
},
|
762 |
-
|
763 |
-
/* Generate the date picker content. */
|
764 |
-
_updateDatepicker: function(inst) {
|
765 |
-
this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
|
766 |
-
instActive = inst; // for delegate hover events
|
767 |
-
inst.dpDiv.empty().append(this._generateHTML(inst));
|
768 |
-
this._attachHandlers(inst);
|
769 |
-
inst.dpDiv.find("." + this._dayOverClass + " a").mouseover();
|
770 |
-
|
771 |
-
var origyearshtml,
|
772 |
-
numMonths = this._getNumberOfMonths(inst),
|
773 |
-
cols = numMonths[1],
|
774 |
-
width = 17;
|
775 |
-
|
776 |
-
inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
|
777 |
-
if (cols > 1) {
|
778 |
-
inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
|
779 |
-
}
|
780 |
-
inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
|
781 |
-
"Class"]("ui-datepicker-multi");
|
782 |
-
inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
|
783 |
-
"Class"]("ui-datepicker-rtl");
|
784 |
-
|
785 |
-
if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
|
786 |
-
inst.input.focus();
|
787 |
-
}
|
788 |
-
|
789 |
-
// deffered render of the years select (to avoid flashes on Firefox)
|
790 |
-
if( inst.yearshtml ){
|
791 |
-
origyearshtml = inst.yearshtml;
|
792 |
-
setTimeout(function(){
|
793 |
-
//assure that inst.yearshtml didn't change.
|
794 |
-
if( origyearshtml === inst.yearshtml && inst.yearshtml ){
|
795 |
-
inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
|
796 |
-
}
|
797 |
-
origyearshtml = inst.yearshtml = null;
|
798 |
-
}, 0);
|
799 |
-
}
|
800 |
-
},
|
801 |
-
|
802 |
-
// #6694 - don't focus the input if it's already focused
|
803 |
-
// this breaks the change event in IE
|
804 |
-
// Support: IE and jQuery <1.9
|
805 |
-
_shouldFocusInput: function( inst ) {
|
806 |
-
return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
|
807 |
-
},
|
808 |
-
|
809 |
-
/* Check positioning to remain on screen. */
|
810 |
-
_checkOffset: function(inst, offset, isFixed) {
|
811 |
-
var dpWidth = inst.dpDiv.outerWidth(),
|
812 |
-
dpHeight = inst.dpDiv.outerHeight(),
|
813 |
-
inputWidth = inst.input ? inst.input.outerWidth() : 0,
|
814 |
-
inputHeight = inst.input ? inst.input.outerHeight() : 0,
|
815 |
-
viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
|
816 |
-
viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
|
817 |
-
|
818 |
-
offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
|
819 |
-
offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
|
820 |
-
offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
|
821 |
-
|
822 |
-
// now check if datepicker is showing outside window viewport - move to a better place if so.
|
823 |
-
offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
|
824 |
-
Math.abs(offset.left + dpWidth - viewWidth) : 0);
|
825 |
-
offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
|
826 |
-
Math.abs(dpHeight + inputHeight) : 0);
|
827 |
-
|
828 |
-
return offset;
|
829 |
-
},
|
830 |
-
|
831 |
-
/* Find an object's position on the screen. */
|
832 |
-
_findPos: function(obj) {
|
833 |
-
var position,
|
834 |
-
inst = this._getInst(obj),
|
835 |
-
isRTL = this._get(inst, "isRTL");
|
836 |
-
|
837 |
-
while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
|
838 |
-
obj = obj[isRTL ? "previousSibling" : "nextSibling"];
|
839 |
-
}
|
840 |
-
|
841 |
-
position = $(obj).offset();
|
842 |
-
return [position.left, position.top];
|
843 |
-
},
|
844 |
-
|
845 |
-
/* Hide the date picker from view.
|
846 |
-
* @param input element - the input field attached to the date picker
|
847 |
-
*/
|
848 |
-
_hideDatepicker: function(input) {
|
849 |
-
var showAnim, duration, postProcess, onClose,
|
850 |
-
inst = this._curInst;
|
851 |
-
|
852 |
-
if (!inst || (input && inst !== $.data(input, PROP_NAME))) {
|
853 |
-
return;
|
854 |
-
}
|
855 |
-
|
856 |
-
if (this._datepickerShowing) {
|
857 |
-
showAnim = this._get(inst, "showAnim");
|
858 |
-
duration = this._get(inst, "duration");
|
859 |
-
postProcess = function() {
|
860 |
-
$.datepicker._tidyDialog(inst);
|
861 |
-
};
|
862 |
-
|
863 |
-
// DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
|
864 |
-
if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
|
865 |
-
inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
|
866 |
-
} else {
|
867 |
-
inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
|
868 |
-
(showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
|
869 |
-
}
|
870 |
-
|
871 |
-
if (!showAnim) {
|
872 |
-
postProcess();
|
873 |
-
}
|
874 |
-
this._datepickerShowing = false;
|
875 |
-
|
876 |
-
onClose = this._get(inst, "onClose");
|
877 |
-
if (onClose) {
|
878 |
-
onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
|
879 |
-
}
|
880 |
-
|
881 |
-
this._lastInput = null;
|
882 |
-
if (this._inDialog) {
|
883 |
-
this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
|
884 |
-
if ($.blockUI) {
|
885 |
-
$.unblockUI();
|
886 |
-
$("body").append(this.dpDiv);
|
887 |
-
}
|
888 |
-
}
|
889 |
-
this._inDialog = false;
|
890 |
-
}
|
891 |
-
},
|
892 |
-
|
893 |
-
/* Tidy up after a dialog display. */
|
894 |
-
_tidyDialog: function(inst) {
|
895 |
-
inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
|
896 |
-
},
|
897 |
-
|
898 |
-
/* Close date picker if clicked elsewhere. */
|
899 |
-
_checkExternalClick: function(event) {
|
900 |
-
if (!$.datepicker._curInst) {
|
901 |
-
return;
|
902 |
-
}
|
903 |
-
|
904 |
-
var $target = $(event.target),
|
905 |
-
inst = $.datepicker._getInst($target[0]);
|
906 |
-
|
907 |
-
if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
|
908 |
-
$target.parents("#" + $.datepicker._mainDivId).length === 0 &&
|
909 |
-
!$target.hasClass($.datepicker.markerClassName) &&
|
910 |
-
!$target.closest("." + $.datepicker._triggerClass).length &&
|
911 |
-
$.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
|
912 |
-
( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
|
913 |
-
$.datepicker._hideDatepicker();
|
914 |
-
}
|
915 |
-
},
|
916 |
-
|
917 |
-
/* Adjust one of the date sub-fields. */
|
918 |
-
_adjustDate: function(id, offset, period) {
|
919 |
-
var target = $(id),
|
920 |
-
inst = this._getInst(target[0]);
|
921 |
-
|
922 |
-
if (this._isDisabledDatepicker(target[0])) {
|
923 |
-
return;
|
924 |
-
}
|
925 |
-
this._adjustInstDate(inst, offset +
|
926 |
-
(period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
|
927 |
-
period);
|
928 |
-
this._updateDatepicker(inst);
|
929 |
-
},
|
930 |
-
|
931 |
-
/* Action for current link. */
|
932 |
-
_gotoToday: function(id) {
|
933 |
-
var date,
|
934 |
-
target = $(id),
|
935 |
-
inst = this._getInst(target[0]);
|
936 |
-
|
937 |
-
if (this._get(inst, "gotoCurrent") && inst.currentDay) {
|
938 |
-
inst.selectedDay = inst.currentDay;
|
939 |
-
inst.drawMonth = inst.selectedMonth = inst.currentMonth;
|
940 |
-
inst.drawYear = inst.selectedYear = inst.currentYear;
|
941 |
-
} else {
|
942 |
-
date = new Date();
|
943 |
-
inst.selectedDay = date.getDate();
|
944 |
-
inst.drawMonth = inst.selectedMonth = date.getMonth();
|
945 |
-
inst.drawYear = inst.selectedYear = date.getFullYear();
|
946 |
-
}
|
947 |
-
this._notifyChange(inst);
|
948 |
-
this._adjustDate(target);
|
949 |
-
},
|
950 |
-
|
951 |
-
/* Action for selecting a new month/year. */
|
952 |
-
_selectMonthYear: function(id, select, period) {
|
953 |
-
var target = $(id),
|
954 |
-
inst = this._getInst(target[0]);
|
955 |
-
|
956 |
-
inst["selected" + (period === "M" ? "Month" : "Year")] =
|
957 |
-
inst["draw" + (period === "M" ? "Month" : "Year")] =
|
958 |
-
parseInt(select.options[select.selectedIndex].value,10);
|
959 |
-
|
960 |
-
this._notifyChange(inst);
|
961 |
-
this._adjustDate(target);
|
962 |
-
},
|
963 |
-
|
964 |
-
/* Action for selecting a day. */
|
965 |
-
_selectDay: function(id, month, year, td) {
|
966 |
-
var inst,
|
967 |
-
target = $(id);
|
968 |
-
|
969 |
-
if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
|
970 |
-
return;
|
971 |
-
}
|
972 |
-
|
973 |
-
inst = this._getInst(target[0]);
|
974 |
-
inst.selectedDay = inst.currentDay = $("a", td).html();
|
975 |
-
inst.selectedMonth = inst.currentMonth = month;
|
976 |
-
inst.selectedYear = inst.currentYear = year;
|
977 |
-
this._selectDate(id, this._formatDate(inst,
|
978 |
-
inst.currentDay, inst.currentMonth, inst.currentYear));
|
979 |
-
},
|
980 |
-
|
981 |
-
/* Erase the input field and hide the date picker. */
|
982 |
-
_clearDate: function(id) {
|
983 |
-
var target = $(id);
|
984 |
-
this._selectDate(target, "");
|
985 |
-
},
|
986 |
-
|
987 |
-
/* Update the input field with the selected date. */
|
988 |
-
_selectDate: function(id, dateStr) {
|
989 |
-
var onSelect,
|
990 |
-
target = $(id),
|
991 |
-
inst = this._getInst(target[0]);
|
992 |
-
|
993 |
-
dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
|
994 |
-
if (inst.input) {
|
995 |
-
inst.input.val(dateStr);
|
996 |
-
}
|
997 |
-
this._updateAlternate(inst);
|
998 |
-
|
999 |
-
onSelect = this._get(inst, "onSelect");
|
1000 |
-
if (onSelect) {
|
1001 |
-
onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
|
1002 |
-
} else if (inst.input) {
|
1003 |
-
inst.input.trigger("change"); // fire the change event
|
1004 |
-
}
|
1005 |
-
|
1006 |
-
if (inst.inline){
|
1007 |
-
this._updateDatepicker(inst);
|
1008 |
-
} else {
|
1009 |
-
this._hideDatepicker();
|
1010 |
-
this._lastInput = inst.input[0];
|
1011 |
-
if (typeof(inst.input[0]) !== "object") {
|
1012 |
-
inst.input.focus(); // restore focus
|
1013 |
-
}
|
1014 |
-
this._lastInput = null;
|
1015 |
-
}
|
1016 |
-
},
|
1017 |
-
|
1018 |
-
/* Update any alternate field to synchronise with the main field. */
|
1019 |
-
_updateAlternate: function(inst) {
|
1020 |
-
var altFormat, date, dateStr,
|
1021 |
-
altField = this._get(inst, "altField");
|
1022 |
-
|
1023 |
-
if (altField) { // update alternate field too
|
1024 |
-
altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
|
1025 |
-
date = this._getDate(inst);
|
1026 |
-
dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
|
1027 |
-
$(altField).each(function() { $(this).val(dateStr); });
|
1028 |
-
}
|
1029 |
-
},
|
1030 |
-
|
1031 |
-
/* Set as beforeShowDay function to prevent selection of weekends.
|
1032 |
-
* @param date Date - the date to customise
|
1033 |
-
* @return [boolean, string] - is this date selectable?, what is its CSS class?
|
1034 |
-
*/
|
1035 |
-
noWeekends: function(date) {
|
1036 |
-
var day = date.getDay();
|
1037 |
-
return [(day > 0 && day < 6), ""];
|
1038 |
-
},
|
1039 |
-
|
1040 |
-
/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
|
1041 |
-
* @param date Date - the date to get the week for
|
1042 |
-
* @return number - the number of the week within the year that contains this date
|
1043 |
-
*/
|
1044 |
-
iso8601Week: function(date) {
|
1045 |
-
var time,
|
1046 |
-
checkDate = new Date(date.getTime());
|
1047 |
-
|
1048 |
-
// Find Thursday of this week starting on Monday
|
1049 |
-
checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
|
1050 |
-
|
1051 |
-
time = checkDate.getTime();
|
1052 |
-
checkDate.setMonth(0); // Compare with Jan 1
|
1053 |
-
checkDate.setDate(1);
|
1054 |
-
return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
|
1055 |
-
},
|
1056 |
-
|
1057 |
-
/* Parse a string value into a date object.
|
1058 |
-
* See formatDate below for the possible formats.
|
1059 |
-
*
|
1060 |
-
* @param format string - the expected format of the date
|
1061 |
-
* @param value string - the date in the above format
|
1062 |
-
* @param settings Object - attributes include:
|
1063 |
-
* shortYearCutoff number - the cutoff year for determining the century (optional)
|
1064 |
-
* dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
|
1065 |
-
* dayNames string[7] - names of the days from Sunday (optional)
|
1066 |
-
* monthNamesShort string[12] - abbreviated names of the months (optional)
|
1067 |
-
* monthNames string[12] - names of the months (optional)
|
1068 |
-
* @return Date - the extracted date value or null if value is blank
|
1069 |
-
*/
|
1070 |
-
parseDate: function (format, value, settings) {
|
1071 |
-
if (format == null || value == null) {
|
1072 |
-
throw "Invalid arguments";
|
1073 |
-
}
|
1074 |
-
|
1075 |
-
value = (typeof value === "object" ? value.toString() : value + "");
|
1076 |
-
if (value === "") {
|
1077 |
-
return null;
|
1078 |
-
}
|
1079 |
-
|
1080 |
-
var iFormat, dim, extra,
|
1081 |
-
iValue = 0,
|
1082 |
-
shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
|
1083 |
-
shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
|
1084 |
-
new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
|
1085 |
-
dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
|
1086 |
-
dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
|
1087 |
-
monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
|
1088 |
-
monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
|
1089 |
-
year = -1,
|
1090 |
-
month = -1,
|
1091 |
-
day = -1,
|
1092 |
-
doy = -1,
|
1093 |
-
literal = false,
|
1094 |
-
date,
|
1095 |
-
// Check whether a format character is doubled
|
1096 |
-
lookAhead = function(match) {
|
1097 |
-
var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
|
1098 |
-
if (matches) {
|
1099 |
-
iFormat++;
|
1100 |
-
}
|
1101 |
-
return matches;
|
1102 |
-
},
|
1103 |
-
// Extract a number from the string value
|
1104 |
-
getNumber = function(match) {
|
1105 |
-
var isDoubled = lookAhead(match),
|
1106 |
-
size = (match === "@" ? 14 : (match === "!" ? 20 :
|
1107 |
-
(match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
|
1108 |
-
digits = new RegExp("^\\d{1," + size + "}"),
|
1109 |
-
num = value.substring(iValue).match(digits);
|
1110 |
-
if (!num) {
|
1111 |
-
throw "Missing number at position " + iValue;
|
1112 |
-
}
|
1113 |
-
iValue += num[0].length;
|
1114 |
-
return parseInt(num[0], 10);
|
1115 |
-
},
|
1116 |
-
// Extract a name from the string value and convert to an index
|
1117 |
-
getName = function(match, shortNames, longNames) {
|
1118 |
-
var index = -1,
|
1119 |
-
names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
|
1120 |
-
return [ [k, v] ];
|
1121 |
-
}).sort(function (a, b) {
|
1122 |
-
return -(a[1].length - b[1].length);
|
1123 |
-
});
|
1124 |
-
|
1125 |
-
$.each(names, function (i, pair) {
|
1126 |
-
var name = pair[1];
|
1127 |
-
if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
|
1128 |
-
index = pair[0];
|
1129 |
-
iValue += name.length;
|
1130 |
-
return false;
|
1131 |
-
}
|
1132 |
-
});
|
1133 |
-
if (index !== -1) {
|
1134 |
-
return index + 1;
|
1135 |
-
} else {
|
1136 |
-
throw "Unknown name at position " + iValue;
|
1137 |
-
}
|
1138 |
-
},
|
1139 |
-
// Confirm that a literal character matches the string value
|
1140 |
-
checkLiteral = function() {
|
1141 |
-
if (value.charAt(iValue) !== format.charAt(iFormat)) {
|
1142 |
-
throw "Unexpected literal at position " + iValue;
|
1143 |
-
}
|
1144 |
-
iValue++;
|
1145 |
-
};
|
1146 |
-
|
1147 |
-
for (iFormat = 0; iFormat < format.length; iFormat++) {
|
1148 |
-
if (literal) {
|
1149 |
-
if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
|
1150 |
-
literal = false;
|
1151 |
-
} else {
|
1152 |
-
checkLiteral();
|
1153 |
-
}
|
1154 |
-
} else {
|
1155 |
-
switch (format.charAt(iFormat)) {
|
1156 |
-
case "d":
|
1157 |
-
day = getNumber("d");
|
1158 |
-
break;
|
1159 |
-
case "D":
|
1160 |
-
getName("D", dayNamesShort, dayNames);
|
1161 |
-
break;
|
1162 |
-
case "o":
|
1163 |
-
doy = getNumber("o");
|
1164 |
-
break;
|
1165 |
-
case "m":
|
1166 |
-
month = getNumber("m");
|
1167 |
-
break;
|
1168 |
-
case "M":
|
1169 |
-
month = getName("M", monthNamesShort, monthNames);
|
1170 |
-
break;
|
1171 |
-
case "y":
|
1172 |
-
year = getNumber("y");
|
1173 |
-
break;
|
1174 |
-
case "@":
|
1175 |
-
date = new Date(getNumber("@"));
|
1176 |
-
year = date.getFullYear();
|
1177 |
-
month = date.getMonth() + 1;
|
1178 |
-
day = date.getDate();
|
1179 |
-
break;
|
1180 |
-
case "!":
|
1181 |
-
date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
|
1182 |
-
year = date.getFullYear();
|
1183 |
-
month = date.getMonth() + 1;
|
1184 |
-
day = date.getDate();
|
1185 |
-
break;
|
1186 |
-
case "'":
|
1187 |
-
if (lookAhead("'")){
|
1188 |
-
checkLiteral();
|
1189 |
-
} else {
|
1190 |
-
literal = true;
|
1191 |
-
}
|
1192 |
-
break;
|
1193 |
-
default:
|
1194 |
-
checkLiteral();
|
1195 |
-
}
|
1196 |
-
}
|
1197 |
-
}
|
1198 |
-
|
1199 |
-
if (iValue < value.length){
|
1200 |
-
extra = value.substr(iValue);
|
1201 |
-
if (!/^\s+/.test(extra)) {
|
1202 |
-
throw "Extra/unparsed characters found in date: " + extra;
|
1203 |
-
}
|
1204 |
-
}
|
1205 |
-
|
1206 |
-
if (year === -1) {
|
1207 |
-
year = new Date().getFullYear();
|
1208 |
-
} else if (year < 100) {
|
1209 |
-
year += new Date().getFullYear() - new Date().getFullYear() % 100 +
|
1210 |
-
(year <= shortYearCutoff ? 0 : -100);
|
1211 |
-
}
|
1212 |
-
|
1213 |
-
if (doy > -1) {
|
1214 |
-
month = 1;
|
1215 |
-
day = doy;
|
1216 |
-
do {
|
1217 |
-
dim = this._getDaysInMonth(year, month - 1);
|
1218 |
-
if (day <= dim) {
|
1219 |
-
break;
|
1220 |
-
}
|
1221 |
-
month++;
|
1222 |
-
day -= dim;
|
1223 |
-
} while (true);
|
1224 |
-
}
|
1225 |
-
|
1226 |
-
date = this._daylightSavingAdjust(new Date(year, month - 1, day));
|
1227 |
-
if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
|
1228 |
-
throw "Invalid date"; // E.g. 31/02/00
|
1229 |
-
}
|
1230 |
-
return date;
|
1231 |
-
},
|
1232 |
-
|
1233 |
-
/* Standard date formats. */
|
1234 |
-
ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
|
1235 |
-
COOKIE: "D, dd M yy",
|
1236 |
-
ISO_8601: "yy-mm-dd",
|
1237 |
-
RFC_822: "D, d M y",
|
1238 |
-
RFC_850: "DD, dd-M-y",
|
1239 |
-
RFC_1036: "D, d M y",
|
1240 |
-
RFC_1123: "D, d M yy",
|
1241 |
-
RFC_2822: "D, d M yy",
|
1242 |
-
RSS: "D, d M y", // RFC 822
|
1243 |
-
TICKS: "!",
|
1244 |
-
TIMESTAMP: "@",
|
1245 |
-
W3C: "yy-mm-dd", // ISO 8601
|
1246 |
-
|
1247 |
-
_ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
|
1248 |
-
Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
|
1249 |
-
|
1250 |
-
/* Format a date object into a string value.
|
1251 |
-
* The format can be combinations of the following:
|
1252 |
-
* d - day of month (no leading zero)
|
1253 |
-
* dd - day of month (two digit)
|
1254 |
-
* o - day of year (no leading zeros)
|
1255 |
-
* oo - day of year (three digit)
|
1256 |
-
* D - day name short
|
1257 |
-
* DD - day name long
|
1258 |
-
* m - month of year (no leading zero)
|
1259 |
-
* mm - month of year (two digit)
|
1260 |
-
* M - month name short
|
1261 |
-
* MM - month name long
|
1262 |
-
* y - year (two digit)
|
1263 |
-
* yy - year (four digit)
|
1264 |
-
* @ - Unix timestamp (ms since 01/01/1970)
|
1265 |
-
* ! - Windows ticks (100ns since 01/01/0001)
|
1266 |
-
* "..." - literal text
|
1267 |
-
* '' - single quote
|
1268 |
-
*
|
1269 |
-
* @param format string - the desired format of the date
|
1270 |
-
* @param date Date - the date value to format
|
1271 |
-
* @param settings Object - attributes include:
|
1272 |
-
* dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
|
1273 |
-
* dayNames string[7] - names of the days from Sunday (optional)
|
1274 |
-
* monthNamesShort string[12] - abbreviated names of the months (optional)
|
1275 |
-
* monthNames string[12] - names of the months (optional)
|
1276 |
-
* @return string - the date in the above format
|
1277 |
-
*/
|
1278 |
-
formatDate: function (format, date, settings) {
|
1279 |
-
if (!date) {
|
1280 |
-
return "";
|
1281 |
-
}
|
1282 |
-
|
1283 |
-
var iFormat,
|
1284 |
-
dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
|
1285 |
-
dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
|
1286 |
-
monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
|
1287 |
-
monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
|
1288 |
-
// Check whether a format character is doubled
|
1289 |
-
lookAhead = function(match) {
|
1290 |
-
var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
|
1291 |
-
if (matches) {
|
1292 |
-
iFormat++;
|
1293 |
-
}
|
1294 |
-
return matches;
|
1295 |
-
},
|
1296 |
-
// Format a number, with leading zero if necessary
|
1297 |
-
formatNumber = function(match, value, len) {
|
1298 |
-
var num = "" + value;
|
1299 |
-
if (lookAhead(match)) {
|
1300 |
-
while (num.length < len) {
|
1301 |
-
num = "0" + num;
|
1302 |
-
}
|
1303 |
-
}
|
1304 |
-
return num;
|
1305 |
-
},
|
1306 |
-
// Format a name, short or long as requested
|
1307 |
-
formatName = function(match, value, shortNames, longNames) {
|
1308 |
-
return (lookAhead(match) ? longNames[value] : shortNames[value]);
|
1309 |
-
},
|
1310 |
-
output = "",
|
1311 |
-
literal = false;
|
1312 |
-
|
1313 |
-
if (date) {
|
1314 |
-
for (iFormat = 0; iFormat < format.length; iFormat++) {
|
1315 |
-
if (literal) {
|
1316 |
-
if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
|
1317 |
-
literal = false;
|
1318 |
-
} else {
|
1319 |
-
output += format.charAt(iFormat);
|
1320 |
-
}
|
1321 |
-
} else {
|
1322 |
-
switch (format.charAt(iFormat)) {
|
1323 |
-
case "d":
|
1324 |
-
output += formatNumber("d", date.getDate(), 2);
|
1325 |
-
break;
|
1326 |
-
case "D":
|
1327 |
-
output += formatName("D", date.getDay(), dayNamesShort, dayNames);
|
1328 |
-
break;
|
1329 |
-
case "o":
|
1330 |
-
output += formatNumber("o",
|
1331 |
-
Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
|
1332 |
-
break;
|
1333 |
-
case "m":
|
1334 |
-
output += formatNumber("m", date.getMonth() + 1, 2);
|
1335 |
-
break;
|
1336 |
-
case "M":
|
1337 |
-
output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
|
1338 |
-
break;
|
1339 |
-
case "y":
|
1340 |
-
output += (lookAhead("y") ? date.getFullYear() :
|
1341 |
-
(date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
|
1342 |
-
break;
|
1343 |
-
case "@":
|
1344 |
-
output += date.getTime();
|
1345 |
-
break;
|
1346 |
-
case "!":
|
1347 |
-
output += date.getTime() * 10000 + this._ticksTo1970;
|
1348 |
-
break;
|
1349 |
-
case "'":
|
1350 |
-
if (lookAhead("'")) {
|
1351 |
-
output += "'";
|
1352 |
-
} else {
|
1353 |
-
literal = true;
|
1354 |
-
}
|
1355 |
-
break;
|
1356 |
-
default:
|
1357 |
-
output += format.charAt(iFormat);
|
1358 |
-
}
|
1359 |
-
}
|
1360 |
-
}
|
1361 |
-
}
|
1362 |
-
return output;
|
1363 |
-
},
|
1364 |
-
|
1365 |
-
/* Extract all possible characters from the date format. */
|
1366 |
-
_possibleChars: function (format) {
|
1367 |
-
var iFormat,
|
1368 |
-
chars = "",
|
1369 |
-
literal = false,
|
1370 |
-
// Check whether a format character is doubled
|
1371 |
-
lookAhead = function(match) {
|
1372 |
-
var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
|
1373 |
-
if (matches) {
|
1374 |
-
iFormat++;
|
1375 |
-
}
|
1376 |
-
return matches;
|
1377 |
-
};
|
1378 |
-
|
1379 |
-
for (iFormat = 0; iFormat < format.length; iFormat++) {
|
1380 |
-
if (literal) {
|
1381 |
-
if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
|
1382 |
-
literal = false;
|
1383 |
-
} else {
|
1384 |
-
chars += format.charAt(iFormat);
|
1385 |
-
}
|
1386 |
-
} else {
|
1387 |
-
switch (format.charAt(iFormat)) {
|
1388 |
-
case "d": case "m": case "y": case "@":
|
1389 |
-
chars += "0123456789";
|
1390 |
-
break;
|
1391 |
-
case "D": case "M":
|
1392 |
-
return null; // Accept anything
|
1393 |
-
case "'":
|
1394 |
-
if (lookAhead("'")) {
|
1395 |
-
chars += "'";
|
1396 |
-
} else {
|
1397 |
-
literal = true;
|
1398 |
-
}
|
1399 |
-
break;
|
1400 |
-
default:
|
1401 |
-
chars += format.charAt(iFormat);
|
1402 |
-
}
|
1403 |
-
}
|
1404 |
-
}
|
1405 |
-
return chars;
|
1406 |
-
},
|
1407 |
-
|
1408 |
-
/* Get a setting value, defaulting if necessary. */
|
1409 |
-
_get: function(inst, name) {
|
1410 |
-
return inst.settings[name] !== undefined ?
|
1411 |
-
inst.settings[name] : this._defaults[name];
|
1412 |
-
},
|
1413 |
-
|
1414 |
-
/* Parse existing date and initialise date picker. */
|
1415 |
-
_setDateFromField: function(inst, noDefault) {
|
1416 |
-
if (inst.input.val() === inst.lastVal) {
|
1417 |
-
return;
|
1418 |
-
}
|
1419 |
-
|
1420 |
-
var dateFormat = this._get(inst, "dateFormat"),
|
1421 |
-
dates = inst.lastVal = inst.input ? inst.input.val() : null,
|
1422 |
-
defaultDate = this._getDefaultDate(inst),
|
1423 |
-
date = defaultDate,
|
1424 |
-
settings = this._getFormatConfig(inst);
|
1425 |
-
|
1426 |
-
try {
|
1427 |
-
date = this.parseDate(dateFormat, dates, settings) || defaultDate;
|
1428 |
-
} catch (event) {
|
1429 |
-
dates = (noDefault ? "" : dates);
|
1430 |
-
}
|
1431 |
-
inst.selectedDay = date.getDate();
|
1432 |
-
inst.drawMonth = inst.selectedMonth = date.getMonth();
|
1433 |
-
inst.drawYear = inst.selectedYear = date.getFullYear();
|
1434 |
-
inst.currentDay = (dates ? date.getDate() : 0);
|
1435 |
-
inst.currentMonth = (dates ? date.getMonth() : 0);
|
1436 |
-
inst.currentYear = (dates ? date.getFullYear() : 0);
|
1437 |
-
this._adjustInstDate(inst);
|
1438 |
-
},
|
1439 |
-
|
1440 |
-
/* Retrieve the default date shown on opening. */
|
1441 |
-
_getDefaultDate: function(inst) {
|
1442 |
-
return this._restrictMinMax(inst,
|
1443 |
-
this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
|
1444 |
-
},
|
1445 |
-
|
1446 |
-
/* A date may be specified as an exact value or a relative one. */
|
1447 |
-
_determineDate: function(inst, date, defaultDate) {
|
1448 |
-
var offsetNumeric = function(offset) {
|
1449 |
-
var date = new Date();
|
1450 |
-
date.setDate(date.getDate() + offset);
|
1451 |
-
return date;
|
1452 |
-
},
|
1453 |
-
offsetString = function(offset) {
|
1454 |
-
try {
|
1455 |
-
return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
|
1456 |
-
offset, $.datepicker._getFormatConfig(inst));
|
1457 |
-
}
|
1458 |
-
catch (e) {
|
1459 |
-
// Ignore
|
1460 |
-
}
|
1461 |
-
|
1462 |
-
var date = (offset.toLowerCase().match(/^c/) ?
|
1463 |
-
$.datepicker._getDate(inst) : null) || new Date(),
|
1464 |
-
year = date.getFullYear(),
|
1465 |
-
month = date.getMonth(),
|
1466 |
-
day = date.getDate(),
|
1467 |
-
pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
|
1468 |
-
matches = pattern.exec(offset);
|
1469 |
-
|
1470 |
-
while (matches) {
|
1471 |
-
switch (matches[2] || "d") {
|
1472 |
-
case "d" : case "D" :
|
1473 |
-
day += parseInt(matches[1],10); break;
|
1474 |
-
case "w" : case "W" :
|
1475 |
-
day += parseInt(matches[1],10) * 7; break;
|
1476 |
-
case "m" : case "M" :
|
1477 |
-
month += parseInt(matches[1],10);
|
1478 |
-
day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
|
1479 |
-
break;
|
1480 |
-
case "y": case "Y" :
|
1481 |
-
year += parseInt(matches[1],10);
|
1482 |
-
day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
|
1483 |
-
break;
|
1484 |
-
}
|
1485 |
-
matches = pattern.exec(offset);
|
1486 |
-
}
|
1487 |
-
return new Date(year, month, day);
|
1488 |
-
},
|
1489 |
-
newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
|
1490 |
-
(typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
|
1491 |
-
|
1492 |
-
newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
|
1493 |
-
if (newDate) {
|
1494 |
-
newDate.setHours(0);
|
1495 |
-
newDate.setMinutes(0);
|
1496 |
-
newDate.setSeconds(0);
|
1497 |
-
newDate.setMilliseconds(0);
|
1498 |
-
}
|
1499 |
-
return this._daylightSavingAdjust(newDate);
|
1500 |
-
},
|
1501 |
-
|
1502 |
-
/* Handle switch to/from daylight saving.
|
1503 |
-
* Hours may be non-zero on daylight saving cut-over:
|
1504 |
-
* > 12 when midnight changeover, but then cannot generate
|
1505 |
-
* midnight datetime, so jump to 1AM, otherwise reset.
|
1506 |
-
* @param date (Date) the date to check
|
1507 |
-
* @return (Date) the corrected date
|
1508 |
-
*/
|
1509 |
-
_daylightSavingAdjust: function(date) {
|
1510 |
-
if (!date) {
|
1511 |
-
return null;
|
1512 |
-
}
|
1513 |
-
date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
|
1514 |
-
return date;
|
1515 |
-
},
|
1516 |
-
|
1517 |
-
/* Set the date(s) directly. */
|
1518 |
-
_setDate: function(inst, date, noChange) {
|
1519 |
-
var clear = !date,
|
1520 |
-
origMonth = inst.selectedMonth,
|
1521 |
-
origYear = inst.selectedYear,
|
1522 |
-
newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
|
1523 |
-
|
1524 |
-
inst.selectedDay = inst.currentDay = newDate.getDate();
|
1525 |
-
inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
|
1526 |
-
inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
|
1527 |
-
if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
|
1528 |
-
this._notifyChange(inst);
|
1529 |
-
}
|
1530 |
-
this._adjustInstDate(inst);
|
1531 |
-
if (inst.input) {
|
1532 |
-
inst.input.val(clear ? "" : this._formatDate(inst));
|
1533 |
-
}
|
1534 |
-
},
|
1535 |
-
|
1536 |
-
/* Retrieve the date(s) directly. */
|
1537 |
-
_getDate: function(inst) {
|
1538 |
-
var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
|
1539 |
-
this._daylightSavingAdjust(new Date(
|
1540 |
-
inst.currentYear, inst.currentMonth, inst.currentDay)));
|
1541 |
-
return startDate;
|
1542 |
-
},
|
1543 |
-
|
1544 |
-
/* Attach the onxxx handlers. These are declared statically so
|
1545 |
-
* they work with static code transformers like Caja.
|
1546 |
-
*/
|
1547 |
-
_attachHandlers: function(inst) {
|
1548 |
-
var stepMonths = this._get(inst, "stepMonths"),
|
1549 |
-
id = "#" + inst.id.replace( /\\\\/g, "\\" );
|
1550 |
-
inst.dpDiv.find("[data-handler]").map(function () {
|
1551 |
-
var handler = {
|
1552 |
-
prev: function () {
|
1553 |
-
$.datepicker._adjustDate(id, -stepMonths, "M");
|
1554 |
-
},
|
1555 |
-
next: function () {
|
1556 |
-
$.datepicker._adjustDate(id, +stepMonths, "M");
|
1557 |
-
},
|
1558 |
-
hide: function () {
|
1559 |
-
$.datepicker._hideDatepicker();
|
1560 |
-
},
|
1561 |
-
today: function () {
|
1562 |
-
$.datepicker._gotoToday(id);
|
1563 |
-
},
|
1564 |
-
selectDay: function () {
|
1565 |
-
$.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
|
1566 |
-
return false;
|
1567 |
-
},
|
1568 |
-
selectMonth: function () {
|
1569 |
-
$.datepicker._selectMonthYear(id, this, "M");
|
1570 |
-
return false;
|
1571 |
-
},
|
1572 |
-
selectYear: function () {
|
1573 |
-
$.datepicker._selectMonthYear(id, this, "Y");
|
1574 |
-
return false;
|
1575 |
-
}
|
1576 |
-
};
|
1577 |
-
$(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
|
1578 |
-
});
|
1579 |
-
},
|
1580 |
-
|
1581 |
-
/* Generate the HTML for the current state of the date picker. */
|
1582 |
-
_generateHTML: function(inst) {
|
1583 |
-
var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
|
1584 |
-
controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
|
1585 |
-
monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
|
1586 |
-
selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
|
1587 |
-
cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
|
1588 |
-
printDate, dRow, tbody, daySettings, otherMonth, unselectable,
|
1589 |
-
tempDate = new Date(),
|
1590 |
-
today = this._daylightSavingAdjust(
|
1591 |
-
new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
|
1592 |
-
isRTL = this._get(inst, "isRTL"),
|
1593 |
-
showButtonPanel = this._get(inst, "showButtonPanel"),
|
1594 |
-
hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
|
1595 |
-
navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
|
1596 |
-
numMonths = this._getNumberOfMonths(inst),
|
1597 |
-
showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
|
1598 |
-
stepMonths = this._get(inst, "stepMonths"),
|
1599 |
-
isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
|
1600 |
-
currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
|
1601 |
-
new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
|
1602 |
-
minDate = this._getMinMaxDate(inst, "min"),
|
1603 |
-
maxDate = this._getMinMaxDate(inst, "max"),
|
1604 |
-
drawMonth = inst.drawMonth - showCurrentAtPos,
|
1605 |
-
drawYear = inst.drawYear;
|
1606 |
-
|
1607 |
-
if (drawMonth < 0) {
|
1608 |
-
drawMonth += 12;
|
1609 |
-
drawYear--;
|
1610 |
-
}
|
1611 |
-
if (maxDate) {
|
1612 |
-
maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
|
1613 |
-
maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
|
1614 |
-
maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
|
1615 |
-
while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
|
1616 |
-
drawMonth--;
|
1617 |
-
if (drawMonth < 0) {
|
1618 |
-
drawMonth = 11;
|
1619 |
-
drawYear--;
|
1620 |
-
}
|
1621 |
-
}
|
1622 |
-
}
|
1623 |
-
inst.drawMonth = drawMonth;
|
1624 |
-
inst.drawYear = drawYear;
|
1625 |
-
|
1626 |
-
prevText = this._get(inst, "prevText");
|
1627 |
-
prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
|
1628 |
-
this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
|
1629 |
-
this._getFormatConfig(inst)));
|
1630 |
-
|
1631 |
-
prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
|
1632 |
-
"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
|
1633 |
-
" title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
|
1634 |
-
(hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>"));
|
1635 |
-
|
1636 |
-
nextText = this._get(inst, "nextText");
|
1637 |
-
nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
|
1638 |
-
this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
|
1639 |
-
this._getFormatConfig(inst)));
|
1640 |
-
|
1641 |
-
next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
|
1642 |
-
"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
|
1643 |
-
" title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
|
1644 |
-
(hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>"));
|
1645 |
-
|
1646 |
-
currentText = this._get(inst, "currentText");
|
1647 |
-
gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
|
1648 |
-
currentText = (!navigationAsDateFormat ? currentText :
|
1649 |
-
this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
|
1650 |
-
|
1651 |
-
controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
|
1652 |
-
this._get(inst, "closeText") + "</button>" : "");
|
1653 |
-
|
1654 |
-
buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
|
1655 |
-
(this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
|
1656 |
-
">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
|
1657 |
-
|
1658 |
-
firstDay = parseInt(this._get(inst, "firstDay"),10);
|
1659 |
-
firstDay = (isNaN(firstDay) ? 0 : firstDay);
|
1660 |
-
|
1661 |
-
showWeek = this._get(inst, "showWeek");
|
1662 |
-
dayNames = this._get(inst, "dayNames");
|
1663 |
-
dayNamesMin = this._get(inst, "dayNamesMin");
|
1664 |
-
monthNames = this._get(inst, "monthNames");
|
1665 |
-
monthNamesShort = this._get(inst, "monthNamesShort");
|
1666 |
-
beforeShowDay = this._get(inst, "beforeShowDay");
|
1667 |
-
showOtherMonths = this._get(inst, "showOtherMonths");
|
1668 |
-
selectOtherMonths = this._get(inst, "selectOtherMonths");
|
1669 |
-
defaultDate = this._getDefaultDate(inst);
|
1670 |
-
html = "";
|
1671 |
-
dow;
|
1672 |
-
for (row = 0; row < numMonths[0]; row++) {
|
1673 |
-
group = "";
|
1674 |
-
this.maxRows = 4;
|
1675 |
-
for (col = 0; col < numMonths[1]; col++) {
|
1676 |
-
selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
|
1677 |
-
cornerClass = " ui-corner-all";
|
1678 |
-
calender = "";
|
1679 |
-
if (isMultiMonth) {
|
1680 |
-
calender += "<div class='ui-datepicker-group";
|
1681 |
-
if (numMonths[1] > 1) {
|
1682 |
-
switch (col) {
|
1683 |
-
case 0: calender += " ui-datepicker-group-first";
|
1684 |
-
cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
|
1685 |
-
case numMonths[1]-1: calender += " ui-datepicker-group-last";
|
1686 |
-
cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
|
1687 |
-
default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
|
1688 |
-
}
|
1689 |
-
}
|
1690 |
-
calender += "'>";
|
1691 |
-
}
|
1692 |
-
calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
|
1693 |
-
(/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
|
1694 |
-
(/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
|
1695 |
-
this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
|
1696 |
-
row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
|
1697 |
-
"</div><table class='ui-datepicker-calendar'><thead>" +
|
1698 |
-
"<tr>";
|
1699 |
-
thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
|
1700 |
-
for (dow = 0; dow < 7; dow++) { // days of the week
|
1701 |
-
day = (dow + firstDay) % 7;
|
1702 |
-
thead += "<th" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
|
1703 |
-
"<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
|
1704 |
-
}
|
1705 |
-
calender += thead + "</tr></thead><tbody>";
|
1706 |
-
daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
|
1707 |
-
if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
|
1708 |
-
inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
|
1709 |
-
}
|
1710 |
-
leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
|
1711 |
-
curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
|
1712 |
-
numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
|
1713 |
-
this.maxRows = numRows;
|
1714 |
-
printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
|
1715 |
-
for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
|
1716 |
-
calender += "<tr>";
|
1717 |
-
tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
|
1718 |
-
this._get(inst, "calculateWeek")(printDate) + "</td>");
|
1719 |
-
for (dow = 0; dow < 7; dow++) { // create date picker days
|
1720 |
-
daySettings = (beforeShowDay ?
|
1721 |
-
beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
|
1722 |
-
otherMonth = (printDate.getMonth() !== drawMonth);
|
1723 |
-
unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
|
1724 |
-
(minDate && printDate < minDate) || (maxDate && printDate > maxDate);
|
1725 |
-
tbody += "<td class='" +
|
1726 |
-
((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
|
1727 |
-
(otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
|
1728 |
-
((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
|
1729 |
-
(defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
|
1730 |
-
// or defaultDate is current printedDate and defaultDate is selectedDate
|
1731 |
-
" " + this._dayOverClass : "") + // highlight selected day
|
1732 |
-
(unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
|
1733 |
-
(otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
|
1734 |
-
(printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
|
1735 |
-
(printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
|
1736 |
-
((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title
|
1737 |
-
(unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
|
1738 |
-
(otherMonth && !showOtherMonths ? " " : // display for other months
|
1739 |
-
(unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
|
1740 |
-
(printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
|
1741 |
-
(printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
|
1742 |
-
(otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
|
1743 |
-
"' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
|
1744 |
-
printDate.setDate(printDate.getDate() + 1);
|
1745 |
-
printDate = this._daylightSavingAdjust(printDate);
|
1746 |
-
}
|
1747 |
-
calender += tbody + "</tr>";
|
1748 |
-
}
|
1749 |
-
drawMonth++;
|
1750 |
-
if (drawMonth > 11) {
|
1751 |
-
drawMonth = 0;
|
1752 |
-
drawYear++;
|
1753 |
-
}
|
1754 |
-
calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
|
1755 |
-
((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
|
1756 |
-
group += calender;
|
1757 |
-
}
|
1758 |
-
html += group;
|
1759 |
-
}
|
1760 |
-
html += buttonPanel;
|
1761 |
-
inst._keyEvent = false;
|
1762 |
-
return html;
|
1763 |
-
},
|
1764 |
-
|
1765 |
-
/* Generate the month and year header. */
|
1766 |
-
_generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
|
1767 |
-
secondary, monthNames, monthNamesShort) {
|
1768 |
-
|
1769 |
-
var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
|
1770 |
-
changeMonth = this._get(inst, "changeMonth"),
|
1771 |
-
changeYear = this._get(inst, "changeYear"),
|
1772 |
-
showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
|
1773 |
-
html = "<div class='ui-datepicker-title'>",
|
1774 |
-
monthHtml = "";
|
1775 |
-
|
1776 |
-
// month selection
|
1777 |
-
if (secondary || !changeMonth) {
|
1778 |
-
monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
|
1779 |
-
} else {
|
1780 |
-
inMinYear = (minDate && minDate.getFullYear() === drawYear);
|
1781 |
-
inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
|
1782 |
-
monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
|
1783 |
-
for ( month = 0; month < 12; month++) {
|
1784 |
-
if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
|
1785 |
-
monthHtml += "<option value='" + month + "'" +
|
1786 |
-
(month === drawMonth ? " selected='selected'" : "") +
|
1787 |
-
">" + monthNamesShort[month] + "</option>";
|
1788 |
-
}
|
1789 |
-
}
|
1790 |
-
monthHtml += "</select>";
|
1791 |
-
}
|
1792 |
-
|
1793 |
-
if (!showMonthAfterYear) {
|
1794 |
-
html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : "");
|
1795 |
-
}
|
1796 |
-
|
1797 |
-
// year selection
|
1798 |
-
if ( !inst.yearshtml ) {
|
1799 |
-
inst.yearshtml = "";
|
1800 |
-
if (secondary || !changeYear) {
|
1801 |
-
html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
|
1802 |
-
} else {
|
1803 |
-
// determine range of years to display
|
1804 |
-
years = this._get(inst, "yearRange").split(":");
|
1805 |
-
thisYear = new Date().getFullYear();
|
1806 |
-
determineYear = function(value) {
|
1807 |
-
var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
|
1808 |
-
(value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
|
1809 |
-
parseInt(value, 10)));
|
1810 |
-
return (isNaN(year) ? thisYear : year);
|
1811 |
-
};
|
1812 |
-
year = determineYear(years[0]);
|
1813 |
-
endYear = Math.max(year, determineYear(years[1] || ""));
|
1814 |
-
year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
|
1815 |
-
endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
|
1816 |
-
inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
|
1817 |
-
for (; year <= endYear; year++) {
|
1818 |
-
inst.yearshtml += "<option value='" + year + "'" +
|
1819 |
-
(year === drawYear ? " selected='selected'" : "") +
|
1820 |
-
">" + year + "</option>";
|
1821 |
-
}
|
1822 |
-
inst.yearshtml += "</select>";
|
1823 |
-
|
1824 |
-
html += inst.yearshtml;
|
1825 |
-
inst.yearshtml = null;
|
1826 |
-
}
|
1827 |
-
}
|
1828 |
-
|
1829 |
-
html += this._get(inst, "yearSuffix");
|
1830 |
-
if (showMonthAfterYear) {
|
1831 |
-
html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml;
|
1832 |
-
}
|
1833 |
-
html += "</div>"; // Close datepicker_header
|
1834 |
-
return html;
|
1835 |
-
},
|
1836 |
-
|
1837 |
-
/* Adjust one of the date sub-fields. */
|
1838 |
-
_adjustInstDate: function(inst, offset, period) {
|
1839 |
-
var year = inst.drawYear + (period === "Y" ? offset : 0),
|
1840 |
-
month = inst.drawMonth + (period === "M" ? offset : 0),
|
1841 |
-
day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
|
1842 |
-
date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
|
1843 |
-
|
1844 |
-
inst.selectedDay = date.getDate();
|
1845 |
-
inst.drawMonth = inst.selectedMonth = date.getMonth();
|
1846 |
-
inst.drawYear = inst.selectedYear = date.getFullYear();
|
1847 |
-
if (period === "M" || period === "Y") {
|
1848 |
-
this._notifyChange(inst);
|
1849 |
-
}
|
1850 |
-
},
|
1851 |
-
|
1852 |
-
/* Ensure a date is within any min/max bounds. */
|
1853 |
-
_restrictMinMax: function(inst, date) {
|
1854 |
-
var minDate = this._getMinMaxDate(inst, "min"),
|
1855 |
-
maxDate = this._getMinMaxDate(inst, "max"),
|
1856 |
-
newDate = (minDate && date < minDate ? minDate : date);
|
1857 |
-
return (maxDate && newDate > maxDate ? maxDate : newDate);
|
1858 |
-
},
|
1859 |
-
|
1860 |
-
/* Notify change of month/year. */
|
1861 |
-
_notifyChange: function(inst) {
|
1862 |
-
var onChange = this._get(inst, "onChangeMonthYear");
|
1863 |
-
if (onChange) {
|
1864 |
-
onChange.apply((inst.input ? inst.input[0] : null),
|
1865 |
-
[inst.selectedYear, inst.selectedMonth + 1, inst]);
|
1866 |
-
}
|
1867 |
-
},
|
1868 |
-
|
1869 |
-
/* Determine the number of months to show. */
|
1870 |
-
_getNumberOfMonths: function(inst) {
|
1871 |
-
var numMonths = this._get(inst, "numberOfMonths");
|
1872 |
-
return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
|
1873 |
-
},
|
1874 |
-
|
1875 |
-
/* Determine the current maximum date - ensure no time components are set. */
|
1876 |
-
_getMinMaxDate: function(inst, minMax) {
|
1877 |
-
return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
|
1878 |
-
},
|
1879 |
-
|
1880 |
-
/* Find the number of days in a given month. */
|
1881 |
-
_getDaysInMonth: function(year, month) {
|
1882 |
-
return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
|
1883 |
-
},
|
1884 |
-
|
1885 |
-
/* Find the day of the week of the first of a month. */
|
1886 |
-
_getFirstDayOfMonth: function(year, month) {
|
1887 |
-
return new Date(year, month, 1).getDay();
|
1888 |
-
},
|
1889 |
-
|
1890 |
-
/* Determines if we should allow a "next/prev" month display change. */
|
1891 |
-
_canAdjustMonth: function(inst, offset, curYear, curMonth) {
|
1892 |
-
var numMonths = this._getNumberOfMonths(inst),
|
1893 |
-
date = this._daylightSavingAdjust(new Date(curYear,
|
1894 |
-
curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
|
1895 |
-
|
1896 |
-
if (offset < 0) {
|
1897 |
-
date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
|
1898 |
-
}
|
1899 |
-
return this._isInRange(inst, date);
|
1900 |
-
},
|
1901 |
-
|
1902 |
-
/* Is the given date in the accepted range? */
|
1903 |
-
_isInRange: function(inst, date) {
|
1904 |
-
var yearSplit, currentYear,
|
1905 |
-
minDate = this._getMinMaxDate(inst, "min"),
|
1906 |
-
maxDate = this._getMinMaxDate(inst, "max"),
|
1907 |
-
minYear = null,
|
1908 |
-
maxYear = null,
|
1909 |
-
years = this._get(inst, "yearRange");
|
1910 |
-
if (years){
|
1911 |
-
yearSplit = years.split(":");
|
1912 |
-
currentYear = new Date().getFullYear();
|
1913 |
-
minYear = parseInt(yearSplit[0], 10);
|
1914 |
-
maxYear = parseInt(yearSplit[1], 10);
|
1915 |
-
if ( yearSplit[0].match(/[+\-].*/) ) {
|
1916 |
-
minYear += currentYear;
|
1917 |
-
}
|
1918 |
-
if ( yearSplit[1].match(/[+\-].*/) ) {
|
1919 |
-
maxYear += currentYear;
|
1920 |
-
}
|
1921 |
-
}
|
1922 |
-
|
1923 |
-
return ((!minDate || date.getTime() >= minDate.getTime()) &&
|
1924 |
-
(!maxDate || date.getTime() <= maxDate.getTime()) &&
|
1925 |
-
(!minYear || date.getFullYear() >= minYear) &&
|
1926 |
-
(!maxYear || date.getFullYear() <= maxYear));
|
1927 |
-
},
|
1928 |
-
|
1929 |
-
/* Provide the configuration settings for formatting/parsing. */
|
1930 |
-
_getFormatConfig: function(inst) {
|
1931 |
-
var shortYearCutoff = this._get(inst, "shortYearCutoff");
|
1932 |
-
shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
|
1933 |
-
new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
|
1934 |
-
return {shortYearCutoff: shortYearCutoff,
|
1935 |
-
dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
|
1936 |
-
monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
|
1937 |
-
},
|
1938 |
-
|
1939 |
-
/* Format the given date for display. */
|
1940 |
-
_formatDate: function(inst, day, month, year) {
|
1941 |
-
if (!day) {
|
1942 |
-
inst.currentDay = inst.selectedDay;
|
1943 |
-
inst.currentMonth = inst.selectedMonth;
|
1944 |
-
inst.currentYear = inst.selectedYear;
|
1945 |
-
}
|
1946 |
-
var date = (day ? (typeof day === "object" ? day :
|
1947 |
-
this._daylightSavingAdjust(new Date(year, month, day))) :
|
1948 |
-
this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
|
1949 |
-
return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
|
1950 |
-
}
|
1951 |
-
});
|
1952 |
-
|
1953 |
-
/*
|
1954 |
-
* Bind hover events for datepicker elements.
|
1955 |
-
* Done via delegate so the binding only occurs once in the lifetime of the parent div.
|
1956 |
-
* Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
|
1957 |
-
*/
|
1958 |
-
function bindHover(dpDiv) {
|
1959 |
-
var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
|
1960 |
-
return dpDiv.delegate(selector, "mouseout", function() {
|
1961 |
-
$(this).removeClass("ui-state-hover");
|
1962 |
-
if (this.className.indexOf("ui-datepicker-prev") !== -1) {
|
1963 |
-
$(this).removeClass("ui-datepicker-prev-hover");
|
1964 |
-
}
|
1965 |
-
if (this.className.indexOf("ui-datepicker-next") !== -1) {
|
1966 |
-
$(this).removeClass("ui-datepicker-next-hover");
|
1967 |
-
}
|
1968 |
-
})
|
1969 |
-
.delegate(selector, "mouseover", function(){
|
1970 |
-
if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
|
1971 |
-
$(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
|
1972 |
-
$(this).addClass("ui-state-hover");
|
1973 |
-
if (this.className.indexOf("ui-datepicker-prev") !== -1) {
|
1974 |
-
$(this).addClass("ui-datepicker-prev-hover");
|
1975 |
-
}
|
1976 |
-
if (this.className.indexOf("ui-datepicker-next") !== -1) {
|
1977 |
-
$(this).addClass("ui-datepicker-next-hover");
|
1978 |
-
}
|
1979 |
-
}
|
1980 |
-
});
|
1981 |
-
}
|
1982 |
-
|
1983 |
-
/* jQuery extend now ignores nulls! */
|
1984 |
-
function extendRemove(target, props) {
|
1985 |
-
$.extend(target, props);
|
1986 |
-
for (var name in props) {
|
1987 |
-
if (props[name] == null) {
|
1988 |
-
target[name] = props[name];
|
1989 |
-
}
|
1990 |
-
}
|
1991 |
-
return target;
|
1992 |
-
}
|
1993 |
-
|
1994 |
-
/* Invoke the datepicker functionality.
|
1995 |
-
@param options string - a command, optionally followed by additional parameters or
|
1996 |
-
Object - settings for attaching new datepicker functionality
|
1997 |
-
@return jQuery object */
|
1998 |
-
$.fn.datepicker = function(options){
|
1999 |
-
|
2000 |
-
/* Verify an empty collection wasn't passed - Fixes #6976 */
|
2001 |
-
if ( !this.length ) {
|
2002 |
-
return this;
|
2003 |
-
}
|
2004 |
-
|
2005 |
-
/* Initialise the date picker. */
|
2006 |
-
if (!$.datepicker.initialized) {
|
2007 |
-
$(document).mousedown($.datepicker._checkExternalClick);
|
2008 |
-
$.datepicker.initialized = true;
|
2009 |
-
}
|
2010 |
-
|
2011 |
-
/* Append datepicker main container to body if not exist. */
|
2012 |
-
if ($("#"+$.datepicker._mainDivId).length === 0) {
|
2013 |
-
$("body").append($.datepicker.dpDiv);
|
2014 |
-
}
|
2015 |
-
|
2016 |
-
var otherArgs = Array.prototype.slice.call(arguments, 1);
|
2017 |
-
if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
|
2018 |
-
return $.datepicker["_" + options + "Datepicker"].
|
2019 |
-
apply($.datepicker, [this[0]].concat(otherArgs));
|
2020 |
-
}
|
2021 |
-
if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
|
2022 |
-
return $.datepicker["_" + options + "Datepicker"].
|
2023 |
-
apply($.datepicker, [this[0]].concat(otherArgs));
|
2024 |
-
}
|
2025 |
-
return this.each(function() {
|
2026 |
-
typeof options === "string" ?
|
2027 |
-
$.datepicker["_" + options + "Datepicker"].
|
2028 |
-
apply($.datepicker, [this].concat(otherArgs)) :
|
2029 |
-
$.datepicker._attachDatepicker(this, options);
|
2030 |
-
});
|
2031 |
-
};
|
2032 |
-
|
2033 |
-
$.datepicker = new Datepicker(); // singleton instance
|
2034 |
-
$.datepicker.initialized = false;
|
2035 |
-
$.datepicker.uuid = new Date().getTime();
|
2036 |
-
$.datepicker.version = "1.10.4";
|
2037 |
-
|
2038 |
-
})(jQuery);
|
1 |
+
/*!
|
2 |
+
* jQuery UI Datepicker 1.10.4
|
3 |
+
* http://jqueryui.com
|
4 |
+
*
|
5 |
+
* Copyright 2014 jQuery Foundation and other contributors
|
6 |
+
* Released under the MIT license.
|
7 |
+
* http://jquery.org/license
|
8 |
+
*
|
9 |
+
* http://api.jqueryui.com/datepicker/
|
10 |
+
*
|
11 |
+
* Depends:
|
12 |
+
* jquery.ui.core.js
|
13 |
+
*/
|
14 |
+
(function( $, undefined ) {
|
15 |
+
|
16 |
+
$.extend($.ui, { datepicker: { version: "1.10.4" } });
|
17 |
+
|
18 |
+
var PROP_NAME = "datepicker",
|
19 |
+
instActive;
|
20 |
+
|
21 |
+
/* Date picker manager.
|
22 |
+
Use the singleton instance of this class, $.datepicker, to interact with the date picker.
|
23 |
+
Settings for (groups of) date pickers are maintained in an instance object,
|
24 |
+
allowing multiple different settings on the same page. */
|
25 |
+
|
26 |
+
function Datepicker() {
|
27 |
+
this._curInst = null; // The current instance in use
|
28 |
+
this._keyEvent = false; // If the last event was a key event
|
29 |
+
this._disabledInputs = []; // List of date picker inputs that have been disabled
|
30 |
+
this._datepickerShowing = false; // True if the popup picker is showing , false if not
|
31 |
+
this._inDialog = false; // True if showing within a "dialog", false if not
|
32 |
+
this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
|
33 |
+
this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
|
34 |
+
this._appendClass = "ui-datepicker-append"; // The name of the append marker class
|
35 |
+
this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
|
36 |
+
this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
|
37 |
+
this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
|
38 |
+
this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
|
39 |
+
this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
|
40 |
+
this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
|
41 |
+
this.regional = []; // Available regional settings, indexed by language code
|
42 |
+
this.regional[""] = { // Default regional settings
|
43 |
+
closeText: "Done", // Display text for close link
|
44 |
+
prevText: "Prev", // Display text for previous month link
|
45 |
+
nextText: "Next", // Display text for next month link
|
46 |
+
currentText: "Today", // Display text for current month link
|
47 |
+
monthNames: ["January","February","March","April","May","June",
|
48 |
+
"July","August","September","October","November","December"], // Names of months for drop-down and formatting
|
49 |
+
monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
|
50 |
+
dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
|
51 |
+
dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
|
52 |
+
dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
|
53 |
+
weekHeader: "Wk", // Column header for week of the year
|
54 |
+
dateFormat: "mm/dd/yy", // See format options on parseDate
|
55 |
+
firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
|
56 |
+
isRTL: false, // True if right-to-left language, false if left-to-right
|
57 |
+
showMonthAfterYear: false, // True if the year select precedes month, false for month then year
|
58 |
+
yearSuffix: "" // Additional text to append to the year in the month headers
|
59 |
+
};
|
60 |
+
this._defaults = { // Global defaults for all the date picker instances
|
61 |
+
showOn: "focus", // "focus" for popup on focus,
|
62 |
+
// "button" for trigger button, or "both" for either
|
63 |
+
showAnim: "fadeIn", // Name of jQuery animation for popup
|
64 |
+
showOptions: {}, // Options for enhanced animations
|
65 |
+
defaultDate: null, // Used when field is blank: actual date,
|
66 |
+
// +/-number for offset from today, null for today
|
67 |
+
appendText: "", // Display text following the input box, e.g. showing the format
|
68 |
+
buttonText: "...", // Text for trigger button
|
69 |
+
buttonImage: "", // URL for trigger button image
|
70 |
+
buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
|
71 |
+
hideIfNoPrevNext: false, // True to hide next/previous month links
|
72 |
+
// if not applicable, false to just disable them
|
73 |
+
navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
|
74 |
+
gotoCurrent: false, // True if today link goes back to current selection instead
|
75 |
+
changeMonth: false, // True if month can be selected directly, false if only prev/next
|
76 |
+
changeYear: false, // True if year can be selected directly, false if only prev/next
|
77 |
+
yearRange: "c-10:c+10", // Range of years to display in drop-down,
|
78 |
+
// either relative to today's year (-nn:+nn), relative to currently displayed year
|
79 |
+
// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
|
80 |
+
showOtherMonths: false, // True to show dates in other months, false to leave blank
|
81 |
+
selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
|
82 |
+
showWeek: false, // True to show week of the year, false to not show it
|
83 |
+
calculateWeek: this.iso8601Week, // How to calculate the week of the year,
|
84 |
+
// takes a Date and returns the number of the week for it
|
85 |
+
shortYearCutoff: "+10", // Short year values < this are in the current century,
|
86 |
+
// > this are in the previous century,
|
87 |
+
// string value starting with "+" for current year + value
|
88 |
+
minDate: null, // The earliest selectable date, or null for no limit
|
89 |
+
maxDate: null, // The latest selectable date, or null for no limit
|
90 |
+
duration: "fast", // Duration of display/closure
|
91 |
+
beforeShowDay: null, // Function that takes a date and returns an array with
|
92 |
+
// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
|
93 |
+
// [2] = cell title (optional), e.g. $.datepicker.noWeekends
|
94 |
+
beforeShow: null, // Function that takes an input field and
|
95 |
+
// returns a set of custom settings for the date picker
|
96 |
+
onSelect: null, // Define a callback function when a date is selected
|
97 |
+
onChangeMonthYear: null, // Define a callback function when the month or year is changed
|
98 |
+
onClose: null, // Define a callback function when the datepicker is closed
|
99 |
+
numberOfMonths: 1, // Number of months to show at a time
|
100 |
+
showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
|
101 |
+
stepMonths: 1, // Number of months to step back/forward
|
102 |
+
stepBigMonths: 12, // Number of months to step back/forward for the big links
|
103 |
+
altField: "", // Selector for an alternate field to store selected dates into
|
104 |
+
altFormat: "", // The date format to use for the alternate field
|
105 |
+
constrainInput: true, // The input is constrained by the current date format
|
106 |
+
showButtonPanel: false, // True to show button panel, false to not show it
|
107 |
+
autoSize: false, // True to size the input for the date format, false to leave as is
|
108 |
+
disabled: false // The initial disabled state
|
109 |
+
};
|
110 |
+
$.extend(this._defaults, this.regional[""]);
|
111 |
+
this.dpDiv = bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
|
112 |
+
}
|
113 |
+
|
114 |
+
$.extend(Datepicker.prototype, {
|
115 |
+
/* Class name added to elements to indicate already configured with a date picker. */
|
116 |
+
markerClassName: "hasDatepicker",
|
117 |
+
|
118 |
+
//Keep track of the maximum number of rows displayed (see #7043)
|
119 |
+
maxRows: 4,
|
120 |
+
|
121 |
+
// TODO rename to "widget" when switching to widget factory
|
122 |
+
_widgetDatepicker: function() {
|
123 |
+
return this.dpDiv;
|
124 |
+
},
|
125 |
+
|
126 |
+
/* Override the default settings for all instances of the date picker.
|
127 |
+
* @param settings object - the new settings to use as defaults (anonymous object)
|
128 |
+
* @return the manager object
|
129 |
+
*/
|
130 |
+
setDefaults: function(settings) {
|
131 |
+
extendRemove(this._defaults, settings || {});
|
132 |
+
return this;
|
133 |
+
},
|
134 |
+
|
135 |
+
/* Attach the date picker to a jQuery selection.
|
136 |
+
* @param target element - the target input field or division or span
|
137 |
+
* @param settings object - the new settings to use for this date picker instance (anonymous)
|
138 |
+
*/
|
139 |
+
_attachDatepicker: function(target, settings) {
|
140 |
+
var nodeName, inline, inst;
|
141 |
+
nodeName = target.nodeName.toLowerCase();
|
142 |
+
inline = (nodeName === "div" || nodeName === "span");
|
143 |
+
if (!target.id) {
|
144 |
+
this.uuid += 1;
|
145 |
+
target.id = "dp" + this.uuid;
|
146 |
+
}
|
147 |
+
inst = this._newInst($(target), inline);
|
148 |
+
inst.settings = $.extend({}, settings || {});
|
149 |
+
if (nodeName === "input") {
|
150 |
+
this._connectDatepicker(target, inst);
|
151 |
+
} else if (inline) {
|
152 |
+
this._inlineDatepicker(target, inst);
|
153 |
+
}
|
154 |
+
},
|
155 |
+
|
156 |
+
/* Create a new instance object. */
|
157 |
+
_newInst: function(target, inline) {
|
158 |
+
var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
|
159 |
+
return {id: id, input: target, // associated target
|
160 |
+
selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
|
161 |
+
drawMonth: 0, drawYear: 0, // month being drawn
|
162 |
+
inline: inline, // is datepicker inline or not
|
163 |
+
dpDiv: (!inline ? this.dpDiv : // presentation div
|
164 |
+
bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
|
165 |
+
},
|
166 |
+
|
167 |
+
/* Attach the date picker to an input field. */
|
168 |
+
_connectDatepicker: function(target, inst) {
|
169 |
+
var input = $(target);
|
170 |
+
inst.append = $([]);
|
171 |
+
inst.trigger = $([]);
|
172 |
+
if (input.hasClass(this.markerClassName)) {
|
173 |
+
return;
|
174 |
+
}
|
175 |
+
this._attachments(input, inst);
|
176 |
+
input.addClass(this.markerClassName).keydown(this._doKeyDown).
|
177 |
+
keypress(this._doKeyPress).keyup(this._doKeyUp);
|
178 |
+
this._autoSize(inst);
|
179 |
+
$.data(target, PROP_NAME, inst);
|
180 |
+
//If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
|
181 |
+
if( inst.settings.disabled ) {
|
182 |
+
this._disableDatepicker( target );
|
183 |
+
}
|
184 |
+
},
|
185 |
+
|
186 |
+
/* Make attachments based on settings. */
|
187 |
+
_attachments: function(input, inst) {
|
188 |
+
var showOn, buttonText, buttonImage,
|
189 |
+
appendText = this._get(inst, "appendText"),
|
190 |
+
isRTL = this._get(inst, "isRTL");
|
191 |
+
|
192 |
+
if (inst.append) {
|
193 |
+
inst.append.remove();
|
194 |
+
}
|
195 |
+
if (appendText) {
|
196 |
+
inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
|
197 |
+
input[isRTL ? "before" : "after"](inst.append);
|
198 |
+
}
|
199 |
+
|
200 |
+
input.unbind("focus", this._showDatepicker);
|
201 |
+
|
202 |
+
if (inst.trigger) {
|
203 |
+
inst.trigger.remove();
|
204 |
+
}
|
205 |
+
|
206 |
+
showOn = this._get(inst, "showOn");
|
207 |
+
if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
|
208 |
+
input.focus(this._showDatepicker);
|
209 |
+
}
|
210 |
+
if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
|
211 |
+
buttonText = this._get(inst, "buttonText");
|
212 |
+
buttonImage = this._get(inst, "buttonImage");
|
213 |
+
inst.trigger = $(this._get(inst, "buttonImageOnly") ?
|
214 |
+
$("<img/>").addClass(this._triggerClass).
|
215 |
+
attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
|
216 |
+
$("<button type='button'></button>").addClass(this._triggerClass).
|
217 |
+
html(!buttonImage ? buttonText : $("<img/>").attr(
|
218 |
+
{ src:buttonImage, alt:buttonText, title:buttonText })));
|
219 |
+
input[isRTL ? "before" : "after"](inst.trigger);
|
220 |
+
inst.trigger.click(function() {
|
221 |
+
if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
|
222 |
+
$.datepicker._hideDatepicker();
|
223 |
+
} else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
|
224 |
+
$.datepicker._hideDatepicker();
|
225 |
+
$.datepicker._showDatepicker(input[0]);
|
226 |
+
} else {
|
227 |
+
$.datepicker._showDatepicker(input[0]);
|
228 |
+
}
|
229 |
+
return false;
|
230 |
+
});
|
231 |
+
}
|
232 |
+
},
|
233 |
+
|
234 |
+
/* Apply the maximum length for the date format. */
|
235 |
+
_autoSize: function(inst) {
|
236 |
+
if (this._get(inst, "autoSize") && !inst.inline) {
|
237 |
+
var findMax, max, maxI, i,
|
238 |
+
date = new Date(2009, 12 - 1, 20), // Ensure double digits
|
239 |
+
dateFormat = this._get(inst, "dateFormat");
|
240 |
+
|
241 |
+
if (dateFormat.match(/[DM]/)) {
|
242 |
+
findMax = function(names) {
|
243 |
+
max = 0;
|
244 |
+
maxI = 0;
|
245 |
+
for (i = 0; i < names.length; i++) {
|
246 |
+
if (names[i].length > max) {
|
247 |
+
max = names[i].length;
|
248 |
+
maxI = i;
|
249 |
+
}
|
250 |
+
}
|
251 |
+
return maxI;
|
252 |
+
};
|
253 |
+
date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
|
254 |
+
"monthNames" : "monthNamesShort"))));
|
255 |
+
date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
|
256 |
+
"dayNames" : "dayNamesShort"))) + 20 - date.getDay());
|
257 |
+
}
|
258 |
+
inst.input.attr("size", this._formatDate(inst, date).length);
|
259 |
+
}
|
260 |
+
},
|
261 |
+
|
262 |
+
/* Attach an inline date picker to a div. */
|
263 |
+
_inlineDatepicker: function(target, inst) {
|
264 |
+
var divSpan = $(target);
|
265 |
+
if (divSpan.hasClass(this.markerClassName)) {
|
266 |
+
return;
|
267 |
+
}
|
268 |
+
divSpan.addClass(this.markerClassName).append(inst.dpDiv);
|
269 |
+
$.data(target, PROP_NAME, inst);
|
270 |
+
this._setDate(inst, this._getDefaultDate(inst), true);
|
271 |
+
this._updateDatepicker(inst);
|
272 |
+
this._updateAlternate(inst);
|
273 |
+
//If disabled option is true, disable the datepicker before showing it (see ticket #5665)
|
274 |
+
if( inst.settings.disabled ) {
|
275 |
+
this._disableDatepicker( target );
|
276 |
+
}
|
277 |
+
// Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
|
278 |
+
// http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
|
279 |
+
inst.dpDiv.css( "display", "block" );
|
280 |
+
},
|
281 |
+
|
282 |
+
/* Pop-up the date picker in a "dialog" box.
|
283 |
+
* @param input element - ignored
|
284 |
+
* @param date string or Date - the initial date to display
|
285 |
+
* @param onSelect function - the function to call when a date is selected
|
286 |
+
* @param settings object - update the dialog date picker instance's settings (anonymous object)
|
287 |
+
* @param pos int[2] - coordinates for the dialog's position within the screen or
|
288 |
+
* event - with x/y coordinates or
|
289 |
+
* leave empty for default (screen centre)
|
290 |
+
* @return the manager object
|
291 |
+
*/
|
292 |
+
_dialogDatepicker: function(input, date, onSelect, settings, pos) {
|
293 |
+
var id, browserWidth, browserHeight, scrollX, scrollY,
|
294 |
+
inst = this._dialogInst; // internal instance
|
295 |
+
|
296 |
+
if (!inst) {
|
297 |
+
this.uuid += 1;
|
298 |
+
id = "dp" + this.uuid;
|
299 |
+
this._dialogInput = $("<input type='text' id='" + id +
|
300 |
+
"' style='position: absolute; top: -100px; width: 0px;'/>");
|
301 |
+
this._dialogInput.keydown(this._doKeyDown);
|
302 |
+
$("body").append(this._dialogInput);
|
303 |
+
inst = this._dialogInst = this._newInst(this._dialogInput, false);
|
304 |
+
inst.settings = {};
|
305 |
+
$.data(this._dialogInput[0], PROP_NAME, inst);
|
306 |
+
}
|
307 |
+
extendRemove(inst.settings, settings || {});
|
308 |
+
date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
|
309 |
+
this._dialogInput.val(date);
|
310 |
+
|
311 |
+
this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
|
312 |
+
if (!this._pos) {
|
313 |
+
browserWidth = document.documentElement.clientWidth;
|
314 |
+
browserHeight = document.documentElement.clientHeight;
|
315 |
+
scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
|
316 |
+
scrollY = document.documentElement.scrollTop || document.body.scrollTop;
|
317 |
+
this._pos = // should use actual width/height below
|
318 |
+
[(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
|
319 |
+
}
|
320 |
+
|
321 |
+
// move input on screen for focus, but hidden behind dialog
|
322 |
+
this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
|
323 |
+
inst.settings.onSelect = onSelect;
|
324 |
+
this._inDialog = true;
|
325 |
+
this.dpDiv.addClass(this._dialogClass);
|
326 |
+
this._showDatepicker(this._dialogInput[0]);
|
327 |
+
if ($.blockUI) {
|
328 |
+
$.blockUI(this.dpDiv);
|
329 |
+
}
|
330 |
+
$.data(this._dialogInput[0], PROP_NAME, inst);
|
331 |
+
return this;
|
332 |
+
},
|
333 |
+
|
334 |
+
/* Detach a datepicker from its control.
|
335 |
+
* @param target element - the target input field or division or span
|
336 |
+
*/
|
337 |
+
_destroyDatepicker: function(target) {
|
338 |
+
var nodeName,
|
339 |
+
$target = $(target),
|
340 |
+
inst = $.data(target, PROP_NAME);
|
341 |
+
|
342 |
+
if (!$target.hasClass(this.markerClassName)) {
|
343 |
+
return;
|
344 |
+
}
|
345 |
+
|
346 |
+
nodeName = target.nodeName.toLowerCase();
|
347 |
+
$.removeData(target, PROP_NAME);
|
348 |
+
if (nodeName === "input") {
|
349 |
+
inst.append.remove();
|
350 |
+
inst.trigger.remove();
|
351 |
+
$target.removeClass(this.markerClassName).
|
352 |
+
unbind("focus", this._showDatepicker).
|
353 |
+
unbind("keydown", this._doKeyDown).
|
354 |
+
unbind("keypress", this._doKeyPress).
|
355 |
+
unbind("keyup", this._doKeyUp);
|
356 |
+
} else if (nodeName === "div" || nodeName === "span") {
|
357 |
+
$target.removeClass(this.markerClassName).empty();
|
358 |
+
}
|
359 |
+
},
|
360 |
+
|
361 |
+
/* Enable the date picker to a jQuery selection.
|
362 |
+
* @param target element - the target input field or division or span
|
363 |
+
*/
|
364 |
+
_enableDatepicker: function(target) {
|
365 |
+
var nodeName, inline,
|
366 |
+
$target = $(target),
|
367 |
+
inst = $.data(target, PROP_NAME);
|
368 |
+
|
369 |
+
if (!$target.hasClass(this.markerClassName)) {
|
370 |
+
return;
|
371 |
+
}
|
372 |
+
|
373 |
+
nodeName = target.nodeName.toLowerCase();
|
374 |
+
if (nodeName === "input") {
|
375 |
+
target.disabled = false;
|
376 |
+
inst.trigger.filter("button").
|
377 |
+
each(function() { this.disabled = false; }).end().
|
378 |
+
filter("img").css({opacity: "1.0", cursor: ""});
|
379 |
+
} else if (nodeName === "div" || nodeName === "span") {
|
380 |
+
inline = $target.children("." + this._inlineClass);
|
381 |
+
inline.children().removeClass("ui-state-disabled");
|
382 |
+
inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
|
383 |
+
prop("disabled", false);
|
384 |
+
}
|
385 |
+
this._disabledInputs = $.map(this._disabledInputs,
|
386 |
+
function(value) { return (value === target ? null : value); }); // delete entry
|
387 |
+
},
|
388 |
+
|
389 |
+
/* Disable the date picker to a jQuery selection.
|
390 |
+
* @param target element - the target input field or division or span
|
391 |
+
*/
|
392 |
+
_disableDatepicker: function(target) {
|
393 |
+
var nodeName, inline,
|
394 |
+
$target = $(target),
|
395 |
+
inst = $.data(target, PROP_NAME);
|
396 |
+
|
397 |
+
if (!$target.hasClass(this.markerClassName)) {
|
398 |
+
return;
|
399 |
+
}
|
400 |
+
|
401 |
+
nodeName = target.nodeName.toLowerCase();
|
402 |
+
if (nodeName === "input") {
|
403 |
+
target.disabled = true;
|
404 |
+
inst.trigger.filter("button").
|
405 |
+
each(function() { this.disabled = true; }).end().
|
406 |
+
filter("img").css({opacity: "0.5", cursor: "default"});
|
407 |
+
} else if (nodeName === "div" || nodeName === "span") {
|
408 |
+
inline = $target.children("." + this._inlineClass);
|
409 |
+
inline.children().addClass("ui-state-disabled");
|
410 |
+
inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
|
411 |
+
prop("disabled", true);
|
412 |
+
}
|
413 |
+
this._disabledInputs = $.map(this._disabledInputs,
|
414 |
+
function(value) { return (value === target ? null : value); }); // delete entry
|
415 |
+
this._disabledInputs[this._disabledInputs.length] = target;
|
416 |
+
},
|
417 |
+
|
418 |
+
/* Is the first field in a jQuery collection disabled as a datepicker?
|
419 |
+
* @param target element - the target input field or division or span
|
420 |
+
* @return boolean - true if disabled, false if enabled
|
421 |
+
*/
|
422 |
+
_isDisabledDatepicker: function(target) {
|
423 |
+
if (!target) {
|
424 |
+
return false;
|
425 |
+
}
|
426 |
+
for (var i = 0; i < this._disabledInputs.length; i++) {
|
427 |
+
if (this._disabledInputs[i] === target) {
|
428 |
+
return true;
|
429 |
+
}
|
430 |
+
}
|
431 |
+
return false;
|
432 |
+
},
|
433 |
+
|
434 |
+
/* Retrieve the instance data for the target control.
|
435 |
+
* @param target element - the target input field or division or span
|
436 |
+
* @return object - the associated instance data
|
437 |
+
* @throws error if a jQuery problem getting data
|
438 |
+
*/
|
439 |
+
_getInst: function(target) {
|
440 |
+
try {
|
441 |
+
return $.data(target, PROP_NAME);
|
442 |
+
}
|
443 |
+
catch (err) {
|
444 |
+
throw "Missing instance data for this datepicker";
|
445 |
+
}
|
446 |
+
},
|
447 |
+
|
448 |
+
/* Update or retrieve the settings for a date picker attached to an input field or division.
|
449 |
+
* @param target element - the target input field or division or span
|
450 |
+
* @param name object - the new settings to update or
|
451 |
+
* string - the name of the setting to change or retrieve,
|
452 |
+
* when retrieving also "all" for all instance settings or
|
453 |
+
* "defaults" for all global defaults
|
454 |
+
* @param value any - the new value for the setting
|
455 |
+
* (omit if above is an object or to retrieve a value)
|
456 |
+
*/
|
457 |
+
_optionDatepicker: function(target, name, value) {
|
458 |
+
var settings, date, minDate, maxDate,
|
459 |
+
inst = this._getInst(target);
|
460 |
+
|
461 |
+
if (arguments.length === 2 && typeof name === "string") {
|
462 |
+
return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
|
463 |
+
(inst ? (name === "all" ? $.extend({}, inst.settings) :
|
464 |
+
this._get(inst, name)) : null));
|
465 |
+
}
|
466 |
+
|
467 |
+
settings = name || {};
|
468 |
+
if (typeof name === "string") {
|
469 |
+
settings = {};
|
470 |
+
settings[name] = value;
|
471 |
+
}
|
472 |
+
|
473 |
+
if (inst) {
|
474 |
+
if (this._curInst === inst) {
|
475 |
+
this._hideDatepicker();
|
476 |
+
}
|
477 |
+
|
478 |
+
date = this._getDateDatepicker(target, true);
|
479 |
+
minDate = this._getMinMaxDate(inst, "min");
|
480 |
+
maxDate = this._getMinMaxDate(inst, "max");
|
481 |
+
extendRemove(inst.settings, settings);
|
482 |
+
// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
|
483 |
+
if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
|
484 |
+
inst.settings.minDate = this._formatDate(inst, minDate);
|
485 |
+
}
|
486 |
+
if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
|
487 |
+
inst.settings.maxDate = this._formatDate(inst, maxDate);
|
488 |
+
}
|
489 |
+
if ( "disabled" in settings ) {
|
490 |
+
if ( settings.disabled ) {
|
491 |
+
this._disableDatepicker(target);
|
492 |
+
} else {
|
493 |
+
this._enableDatepicker(target);
|
494 |
+
}
|
495 |
+
}
|
496 |
+
this._attachments($(target), inst);
|
497 |
+
this._autoSize(inst);
|
498 |
+
this._setDate(inst, date);
|
499 |
+
this._updateAlternate(inst);
|
500 |
+
this._updateDatepicker(inst);
|
501 |
+
}
|
502 |
+
},
|
503 |
+
|
504 |
+
// change method deprecated
|
505 |
+
_changeDatepicker: function(target, name, value) {
|
506 |
+
this._optionDatepicker(target, name, value);
|
507 |
+
},
|
508 |
+
|
509 |
+
/* Redraw the date picker attached to an input field or division.
|
510 |
+
* @param target element - the target input field or division or span
|
511 |
+
*/
|
512 |
+
_refreshDatepicker: function(target) {
|
513 |
+
var inst = this._getInst(target);
|
514 |
+
if (inst) {
|
515 |
+
this._updateDatepicker(inst);
|
516 |
+
}
|
517 |
+
},
|
518 |
+
|
519 |
+
/* Set the dates for a jQuery selection.
|
520 |
+
* @param target element - the target input field or division or span
|
521 |
+
* @param date Date - the new date
|
522 |
+
*/
|
523 |
+
_setDateDatepicker: function(target, date) {
|
524 |
+
var inst = this._getInst(target);
|
525 |
+
if (inst) {
|
526 |
+
this._setDate(inst, date);
|
527 |
+
this._updateDatepicker(inst);
|
528 |
+
this._updateAlternate(inst);
|
529 |
+
}
|
530 |
+
},
|
531 |
+
|
532 |
+
/* Get the date(s) for the first entry in a jQuery selection.
|
533 |
+
* @param target element - the target input field or division or span
|
534 |
+
* @param noDefault boolean - true if no default date is to be used
|
535 |
+
* @return Date - the current date
|
536 |
+
*/
|
537 |
+
_getDateDatepicker: function(target, noDefault) {
|
538 |
+
var inst = this._getInst(target);
|
539 |
+
if (inst && !inst.inline) {
|
540 |
+
this._setDateFromField(inst, noDefault);
|
541 |
+
}
|
542 |
+
return (inst ? this._getDate(inst) : null);
|
543 |
+
},
|
544 |
+
|
545 |
+
/* Handle keystrokes. */
|
546 |
+
_doKeyDown: function(event) {
|
547 |
+
var onSelect, dateStr, sel,
|
548 |
+
inst = $.datepicker._getInst(event.target),
|
549 |
+
handled = true,
|
550 |
+
isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
|
551 |
+
|
552 |
+
inst._keyEvent = true;
|
553 |
+
if ($.datepicker._datepickerShowing) {
|
554 |
+
switch (event.keyCode) {
|
555 |
+
case 9: $.datepicker._hideDatepicker();
|
556 |
+
handled = false;
|
557 |
+
break; // hide on tab out
|
558 |
+
case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
|
559 |
+
$.datepicker._currentClass + ")", inst.dpDiv);
|
560 |
+
if (sel[0]) {
|
561 |
+
$.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
|
562 |
+
}
|
563 |
+
|
564 |
+
onSelect = $.datepicker._get(inst, "onSelect");
|
565 |
+
if (onSelect) {
|
566 |
+
dateStr = $.datepicker._formatDate(inst);
|
567 |
+
|
568 |
+
// trigger custom callback
|
569 |
+
onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
|
570 |
+
} else {
|
571 |
+
$.datepicker._hideDatepicker();
|
572 |
+
}
|
573 |
+
|
574 |
+
return false; // don't submit the form
|
575 |
+
case 27: $.datepicker._hideDatepicker();
|
576 |
+
break; // hide on escape
|
577 |
+
case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
|
578 |
+
-$.datepicker._get(inst, "stepBigMonths") :
|
579 |
+
-$.datepicker._get(inst, "stepMonths")), "M");
|
580 |
+
break; // previous month/year on page up/+ ctrl
|
581 |
+
case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
|
582 |
+
+$.datepicker._get(inst, "stepBigMonths") :
|
583 |
+
+$.datepicker._get(inst, "stepMonths")), "M");
|
584 |
+
break; // next month/year on page down/+ ctrl
|
585 |
+
case 35: if (event.ctrlKey || event.metaKey) {
|
586 |
+
$.datepicker._clearDate(event.target);
|
587 |
+
}
|
588 |
+
handled = event.ctrlKey || event.metaKey;
|
589 |
+
break; // clear on ctrl or command +end
|
590 |
+
case 36: if (event.ctrlKey || event.metaKey) {
|
591 |
+
$.datepicker._gotoToday(event.target);
|
592 |
+
}
|
593 |
+
handled = event.ctrlKey || event.metaKey;
|
594 |
+
break; // current on ctrl or command +home
|
595 |
+
case 37: if (event.ctrlKey || event.metaKey) {
|
596 |
+
$.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
|
597 |
+
}
|
598 |
+
handled = event.ctrlKey || event.metaKey;
|
599 |
+
// -1 day on ctrl or command +left
|
600 |
+
if (event.originalEvent.altKey) {
|
601 |
+
$.datepicker._adjustDate(event.target, (event.ctrlKey ?
|
602 |
+
-$.datepicker._get(inst, "stepBigMonths") :
|
603 |
+
-$.datepicker._get(inst, "stepMonths")), "M");
|
604 |
+
}
|
605 |
+
// next month/year on alt +left on Mac
|
606 |
+
break;
|
607 |
+
case 38: if (event.ctrlKey || event.metaKey) {
|
608 |
+
$.datepicker._adjustDate(event.target, -7, "D");
|
609 |
+
}
|
610 |
+
handled = event.ctrlKey || event.metaKey;
|
611 |
+
break; // -1 week on ctrl or command +up
|
612 |
+
case 39: if (event.ctrlKey || event.metaKey) {
|
613 |
+
$.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
|
614 |
+
}
|
615 |
+
handled = event.ctrlKey || event.metaKey;
|
616 |
+
// +1 day on ctrl or command +right
|
617 |
+
if (event.originalEvent.altKey) {
|
618 |
+
$.datepicker._adjustDate(event.target, (event.ctrlKey ?
|
619 |
+
+$.datepicker._get(inst, "stepBigMonths") :
|
620 |
+
+$.datepicker._get(inst, "stepMonths")), "M");
|
621 |
+
}
|
622 |
+
// next month/year on alt +right
|
623 |
+
break;
|
624 |
+
case 40: if (event.ctrlKey || event.metaKey) {
|
625 |
+
$.datepicker._adjustDate(event.target, +7, "D");
|
626 |
+
}
|
627 |
+
handled = event.ctrlKey || event.metaKey;
|
628 |
+
break; // +1 week on ctrl or command +down
|
629 |
+
default: handled = false;
|
630 |
+
}
|
631 |
+
} else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
|
632 |
+
$.datepicker._showDatepicker(this);
|
633 |
+
} else {
|
634 |
+
handled = false;
|
635 |
+
}
|
636 |
+
|
637 |
+
if (handled) {
|
638 |
+
event.preventDefault();
|
639 |
+
event.stopPropagation();
|
640 |
+
}
|
641 |
+
},
|
642 |
+
|
643 |
+
/* Filter entered characters - based on date format. */
|
644 |
+
_doKeyPress: function(event) {
|
645 |
+
var chars, chr,
|
646 |
+
inst = $.datepicker._getInst(event.target);
|
647 |
+
|
648 |
+
if ($.datepicker._get(inst, "constrainInput")) {
|
649 |
+
chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
|
650 |
+
chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
|
651 |
+
return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
|
652 |
+
}
|
653 |
+
},
|
654 |
+
|
655 |
+
/* Synchronise manual entry and field/alternate field. */
|
656 |
+
_doKeyUp: function(event) {
|
657 |
+
var date,
|
658 |
+
inst = $.datepicker._getInst(event.target);
|
659 |
+
|
660 |
+
if (inst.input.val() !== inst.lastVal) {
|
661 |
+
try {
|
662 |
+
date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
|
663 |
+
(inst.input ? inst.input.val() : null),
|
664 |
+
$.datepicker._getFormatConfig(inst));
|
665 |
+
|
666 |
+
if (date) { // only if valid
|
667 |
+
$.datepicker._setDateFromField(inst);
|
668 |
+
$.datepicker._updateAlternate(inst);
|
669 |
+
$.datepicker._updateDatepicker(inst);
|
670 |
+
}
|
671 |
+
}
|
672 |
+
catch (err) {
|
673 |
+
}
|
674 |
+
}
|
675 |
+
return true;
|
676 |
+
},
|
677 |
+
|
678 |
+
/* Pop-up the date picker for a given input field.
|
679 |
+
* If false returned from beforeShow event handler do not show.
|
680 |
+
* @param input element - the input field attached to the date picker or
|
681 |
+
* event - if triggered by focus
|
682 |
+
*/
|
683 |
+
_showDatepicker: function(input) {
|
684 |
+
input = input.target || input;
|
685 |
+
if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
|
686 |
+
input = $("input", input.parentNode)[0];
|
687 |
+
}
|
688 |
+
|
689 |
+
if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
|
690 |
+
return;
|
691 |
+
}
|
692 |
+
|
693 |
+
var inst, beforeShow, beforeShowSettings, isFixed,
|
694 |
+
offset, showAnim, duration;
|
695 |
+
|
696 |
+
inst = $.datepicker._getInst(input);
|
697 |
+
if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
|
698 |
+
$.datepicker._curInst.dpDiv.stop(true, true);
|
699 |
+
if ( inst && $.datepicker._datepickerShowing ) {
|
700 |
+
$.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
|
701 |
+
}
|
702 |
+
}
|
703 |
+
|
704 |
+
beforeShow = $.datepicker._get(inst, "beforeShow");
|
705 |
+
beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
|
706 |
+
if(beforeShowSettings === false){
|
707 |
+
return;
|
708 |
+
}
|
709 |
+
extendRemove(inst.settings, beforeShowSettings);
|
710 |
+
|
711 |
+
inst.lastVal = null;
|
712 |
+
$.datepicker._lastInput = input;
|
713 |
+
$.datepicker._setDateFromField(inst);
|
714 |
+
|
715 |
+
if ($.datepicker._inDialog) { // hide cursor
|
716 |
+
input.value = "";
|
717 |
+
}
|
718 |
+
if (!$.datepicker._pos) { // position below input
|
719 |
+
$.datepicker._pos = $.datepicker._findPos(input);
|
720 |
+
$.datepicker._pos[1] += input.offsetHeight; // add the height
|
721 |
+
}
|
722 |
+
|
723 |
+
isFixed = false;
|
724 |
+
$(input).parents().each(function() {
|
725 |
+
isFixed |= $(this).css("position") === "fixed";
|
726 |
+
return !isFixed;
|
727 |
+
});
|
728 |
+
|
729 |
+
offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
|
730 |
+
$.datepicker._pos = null;
|
731 |
+
//to avoid flashes on Firefox
|
732 |
+
inst.dpDiv.empty();
|
733 |
+
// determine sizing offscreen
|
734 |
+
inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
|
735 |
+
$.datepicker._updateDatepicker(inst);
|
736 |
+
// fix width for dynamic number of date pickers
|
737 |
+
// and adjust position before showing
|
738 |
+
offset = $.datepicker._checkOffset(inst, offset, isFixed);
|
739 |
+
inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
|
740 |
+
"static" : (isFixed ? "fixed" : "absolute")), display: "none",
|
741 |
+
left: offset.left + "px", top: offset.top + "px"});
|
742 |
+
|
743 |
+
if (!inst.inline) {
|
744 |
+
showAnim = $.datepicker._get(inst, "showAnim");
|
745 |
+
duration = $.datepicker._get(inst, "duration");
|
746 |
+
inst.dpDiv.zIndex($(input).zIndex()+1);
|
747 |
+
$.datepicker._datepickerShowing = true;
|
748 |
+
|
749 |
+
if ( $.effects && $.effects.effect[ showAnim ] ) {
|
750 |
+
inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
|
751 |
+
} else {
|
752 |
+
inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
|
753 |
+
}
|
754 |
+
|
755 |
+
if ( $.datepicker._shouldFocusInput( inst ) ) {
|
756 |
+
inst.input.focus();
|
757 |
+
}
|
758 |
+
|
759 |
+
$.datepicker._curInst = inst;
|
760 |
+
}
|
761 |
+
},
|
762 |
+
|
763 |
+
/* Generate the date picker content. */
|
764 |
+
_updateDatepicker: function(inst) {
|
765 |
+
this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
|
766 |
+
instActive = inst; // for delegate hover events
|
767 |
+
inst.dpDiv.empty().append(this._generateHTML(inst));
|
768 |
+
this._attachHandlers(inst);
|
769 |
+
inst.dpDiv.find("." + this._dayOverClass + " a").mouseover();
|
770 |
+
|
771 |
+
var origyearshtml,
|
772 |
+
numMonths = this._getNumberOfMonths(inst),
|
773 |
+
cols = numMonths[1],
|
774 |
+
width = 17;
|
775 |
+
|
776 |
+
inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
|
777 |
+
if (cols > 1) {
|
778 |
+
inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
|
779 |
+
}
|
780 |
+
inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
|
781 |
+
"Class"]("ui-datepicker-multi");
|
782 |
+
inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
|
783 |
+
"Class"]("ui-datepicker-rtl");
|
784 |
+
|
785 |
+
if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
|
786 |
+
inst.input.focus();
|
787 |
+
}
|
788 |
+
|
789 |
+
// deffered render of the years select (to avoid flashes on Firefox)
|
790 |
+
if( inst.yearshtml ){
|
791 |
+
origyearshtml = inst.yearshtml;
|
792 |
+
setTimeout(function(){
|
793 |
+
//assure that inst.yearshtml didn't change.
|
794 |
+
if( origyearshtml === inst.yearshtml && inst.yearshtml ){
|
795 |
+
inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
|
796 |
+
}
|
797 |
+
origyearshtml = inst.yearshtml = null;
|
798 |
+
}, 0);
|
799 |
+
}
|
800 |
+
},
|
801 |
+
|
802 |
+
// #6694 - don't focus the input if it's already focused
|
803 |
+
// this breaks the change event in IE
|
804 |
+
// Support: IE and jQuery <1.9
|
805 |
+
_shouldFocusInput: function( inst ) {
|
806 |
+
return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
|
807 |
+
},
|
808 |
+
|
809 |
+
/* Check positioning to remain on screen. */
|
810 |
+
_checkOffset: function(inst, offset, isFixed) {
|
811 |
+
var dpWidth = inst.dpDiv.outerWidth(),
|
812 |
+
dpHeight = inst.dpDiv.outerHeight(),
|
813 |
+
inputWidth = inst.input ? inst.input.outerWidth() : 0,
|
814 |
+
inputHeight = inst.input ? inst.input.outerHeight() : 0,
|
815 |
+
viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
|
816 |
+
viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
|
817 |
+
|
818 |
+
offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
|
819 |
+
offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
|
820 |
+
offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
|
821 |
+
|
822 |
+
// now check if datepicker is showing outside window viewport - move to a better place if so.
|
823 |
+
offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
|
824 |
+
Math.abs(offset.left + dpWidth - viewWidth) : 0);
|
825 |
+
offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
|
826 |
+
Math.abs(dpHeight + inputHeight) : 0);
|
827 |
+
|
828 |
+
return offset;
|
829 |
+
},
|
830 |
+
|
831 |
+
/* Find an object's position on the screen. */
|
832 |
+
_findPos: function(obj) {
|
833 |
+
var position,
|
834 |
+
inst = this._getInst(obj),
|
835 |
+
isRTL = this._get(inst, "isRTL");
|
836 |
+
|
837 |
+
while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
|
838 |
+
obj = obj[isRTL ? "previousSibling" : "nextSibling"];
|
839 |
+
}
|
840 |
+
|
841 |
+
position = $(obj).offset();
|
842 |
+
return [position.left, position.top];
|
843 |
+
},
|
844 |
+
|
845 |
+
/* Hide the date picker from view.
|
846 |
+
* @param input element - the input field attached to the date picker
|
847 |
+
*/
|
848 |
+
_hideDatepicker: function(input) {
|
849 |
+
var showAnim, duration, postProcess, onClose,
|
850 |
+
inst = this._curInst;
|
851 |
+
|
852 |
+
if (!inst || (input && inst !== $.data(input, PROP_NAME))) {
|
853 |
+
return;
|
854 |
+
}
|
855 |
+
|
856 |
+
if (this._datepickerShowing) {
|
857 |
+
showAnim = this._get(inst, "showAnim");
|
858 |
+
duration = this._get(inst, "duration");
|
859 |
+
postProcess = function() {
|
860 |
+
$.datepicker._tidyDialog(inst);
|
861 |
+
};
|
862 |
+
|
863 |
+
// DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
|
864 |
+
if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
|
865 |
+
inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
|
866 |
+
} else {
|
867 |
+
inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
|
868 |
+
(showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
|
869 |
+
}
|
870 |
+
|
871 |
+
if (!showAnim) {
|
872 |
+
postProcess();
|
873 |
+
}
|
874 |
+
this._datepickerShowing = false;
|
875 |
+
|
876 |
+
onClose = this._get(inst, "onClose");
|
877 |
+
if (onClose) {
|
878 |
+
onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
|
879 |
+
}
|
880 |
+
|
881 |
+
this._lastInput = null;
|
882 |
+
if (this._inDialog) {
|
883 |
+
this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
|
884 |
+
if ($.blockUI) {
|
885 |
+
$.unblockUI();
|
886 |
+
$("body").append(this.dpDiv);
|
887 |
+
}
|
888 |
+
}
|
889 |
+
this._inDialog = false;
|
890 |
+
}
|
891 |
+
},
|
892 |
+
|
893 |
+
/* Tidy up after a dialog display. */
|
894 |
+
_tidyDialog: function(inst) {
|
895 |
+
inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
|
896 |
+
},
|
897 |
+
|
898 |
+
/* Close date picker if clicked elsewhere. */
|
899 |
+
_checkExternalClick: function(event) {
|
900 |
+
if (!$.datepicker._curInst) {
|
901 |
+
return;
|
902 |
+
}
|
903 |
+
|
904 |
+
var $target = $(event.target),
|
905 |
+
inst = $.datepicker._getInst($target[0]);
|
906 |
+
|
907 |
+
if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
|
908 |
+
$target.parents("#" + $.datepicker._mainDivId).length === 0 &&
|
909 |
+
!$target.hasClass($.datepicker.markerClassName) &&
|
910 |
+
!$target.closest("." + $.datepicker._triggerClass).length &&
|
911 |
+
$.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
|
912 |
+
( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
|
913 |
+
$.datepicker._hideDatepicker();
|
914 |
+
}
|
915 |
+
},
|
916 |
+
|
917 |
+
/* Adjust one of the date sub-fields. */
|
918 |
+
_adjustDate: function(id, offset, period) {
|
919 |
+
var target = $(id),
|
920 |
+
inst = this._getInst(target[0]);
|
921 |
+
|
922 |
+
if (this._isDisabledDatepicker(target[0])) {
|
923 |
+
return;
|
924 |
+
}
|
925 |
+
this._adjustInstDate(inst, offset +
|
926 |
+
(period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
|
927 |
+
period);
|
928 |
+
this._updateDatepicker(inst);
|
929 |
+
},
|
930 |
+
|
931 |
+
/* Action for current link. */
|
932 |
+
_gotoToday: function(id) {
|
933 |
+
var date,
|
934 |
+
target = $(id),
|
935 |
+
inst = this._getInst(target[0]);
|
936 |
+
|
937 |
+
if (this._get(inst, "gotoCurrent") && inst.currentDay) {
|
938 |
+
inst.selectedDay = inst.currentDay;
|
939 |
+
inst.drawMonth = inst.selectedMonth = inst.currentMonth;
|
940 |
+
inst.drawYear = inst.selectedYear = inst.currentYear;
|
941 |
+
} else {
|
942 |
+
date = new Date();
|
943 |
+
inst.selectedDay = date.getDate();
|
944 |
+
inst.drawMonth = inst.selectedMonth = date.getMonth();
|
945 |
+
inst.drawYear = inst.selectedYear = date.getFullYear();
|
946 |
+
}
|
947 |
+
this._notifyChange(inst);
|
948 |
+
this._adjustDate(target);
|
949 |
+
},
|
950 |
+
|
951 |
+
/* Action for selecting a new month/year. */
|
952 |
+
_selectMonthYear: function(id, select, period) {
|
953 |
+
var target = $(id),
|
954 |
+
inst = this._getInst(target[0]);
|
955 |
+
|
956 |
+
inst["selected" + (period === "M" ? "Month" : "Year")] =
|
957 |
+
inst["draw" + (period === "M" ? "Month" : "Year")] =
|
958 |
+
parseInt(select.options[select.selectedIndex].value,10);
|
959 |
+
|
960 |
+
this._notifyChange(inst);
|
961 |
+
this._adjustDate(target);
|
962 |
+
},
|
963 |
+
|
964 |
+
/* Action for selecting a day. */
|
965 |
+
_selectDay: function(id, month, year, td) {
|
966 |
+
var inst,
|
967 |
+
target = $(id);
|
968 |
+
|
969 |
+
if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
|
970 |
+
return;
|
971 |
+
}
|
972 |
+
|
973 |
+
inst = this._getInst(target[0]);
|
974 |
+
inst.selectedDay = inst.currentDay = $("a", td).html();
|
975 |
+
inst.selectedMonth = inst.currentMonth = month;
|
976 |
+
inst.selectedYear = inst.currentYear = year;
|
977 |
+
this._selectDate(id, this._formatDate(inst,
|
978 |
+
inst.currentDay, inst.currentMonth, inst.currentYear));
|
979 |
+
},
|
980 |
+
|
981 |
+
/* Erase the input field and hide the date picker. */
|
982 |
+
_clearDate: function(id) {
|
983 |
+
var target = $(id);
|
984 |
+
this._selectDate(target, "");
|
985 |
+
},
|
986 |
+
|
987 |
+
/* Update the input field with the selected date. */
|
988 |
+
_selectDate: function(id, dateStr) {
|
989 |
+
var onSelect,
|
990 |
+
target = $(id),
|
991 |
+
inst = this._getInst(target[0]);
|
992 |
+
|
993 |
+
dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
|
994 |
+
if (inst.input) {
|
995 |
+
inst.input.val(dateStr);
|
996 |
+
}
|
997 |
+
this._updateAlternate(inst);
|
998 |
+
|
999 |
+
onSelect = this._get(inst, "onSelect");
|
1000 |
+
if (onSelect) {
|
1001 |
+
onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
|
1002 |
+
} else if (inst.input) {
|
1003 |
+
inst.input.trigger("change"); // fire the change event
|
1004 |
+
}
|
1005 |
+
|
1006 |
+
if (inst.inline){
|
1007 |
+
this._updateDatepicker(inst);
|
1008 |
+
} else {
|
1009 |
+
this._hideDatepicker();
|
1010 |
+
this._lastInput = inst.input[0];
|
1011 |
+
if (typeof(inst.input[0]) !== "object") {
|
1012 |
+
inst.input.focus(); // restore focus
|
1013 |
+
}
|
1014 |
+
this._lastInput = null;
|
1015 |
+
}
|
1016 |
+
},
|
1017 |
+
|
1018 |
+
/* Update any alternate field to synchronise with the main field. */
|
1019 |
+
_updateAlternate: function(inst) {
|
1020 |
+
var altFormat, date, dateStr,
|
1021 |
+
altField = this._get(inst, "altField");
|
1022 |
+
|
1023 |
+
if (altField) { // update alternate field too
|
1024 |
+
altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
|
1025 |
+
date = this._getDate(inst);
|
1026 |
+
dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
|
1027 |
+
$(altField).each(function() { $(this).val(dateStr); });
|
1028 |
+
}
|
1029 |
+
},
|
1030 |
+
|
1031 |
+
/* Set as beforeShowDay function to prevent selection of weekends.
|
1032 |
+
* @param date Date - the date to customise
|
1033 |
+
* @return [boolean, string] - is this date selectable?, what is its CSS class?
|
1034 |
+
*/
|
1035 |
+
noWeekends: function(date) {
|
1036 |
+
var day = date.getDay();
|
1037 |
+
return [(day > 0 && day < 6), ""];
|
1038 |
+
},
|
1039 |
+
|
1040 |
+
/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
|
1041 |
+
* @param date Date - the date to get the week for
|
1042 |
+
* @return number - the number of the week within the year that contains this date
|
1043 |
+
*/
|
1044 |
+
iso8601Week: function(date) {
|
1045 |
+
var time,
|
1046 |
+
checkDate = new Date(date.getTime());
|
1047 |
+
|
1048 |
+
// Find Thursday of this week starting on Monday
|
1049 |
+
checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
|
1050 |
+
|
1051 |
+
time = checkDate.getTime();
|
1052 |
+
checkDate.setMonth(0); // Compare with Jan 1
|
1053 |
+
checkDate.setDate(1);
|
1054 |
+
return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
|
1055 |
+
},
|
1056 |
+
|
1057 |
+
/* Parse a string value into a date object.
|
1058 |
+
* See formatDate below for the possible formats.
|
1059 |
+
*
|
1060 |
+
* @param format string - the expected format of the date
|
1061 |
+
* @param value string - the date in the above format
|
1062 |
+
* @param settings Object - attributes include:
|
1063 |
+
* shortYearCutoff number - the cutoff year for determining the century (optional)
|
1064 |
+
* dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
|
1065 |
+
* dayNames string[7] - names of the days from Sunday (optional)
|
1066 |
+
* monthNamesShort string[12] - abbreviated names of the months (optional)
|
1067 |
+
* monthNames string[12] - names of the months (optional)
|
1068 |
+
* @return Date - the extracted date value or null if value is blank
|
1069 |
+
*/
|
1070 |
+
parseDate: function (format, value, settings) {
|
1071 |
+
if (format == null || value == null) {
|
1072 |
+
throw "Invalid arguments";
|
1073 |
+
}
|
1074 |
+
|
1075 |
+
value = (typeof value === "object" ? value.toString() : value + "");
|
1076 |
+
if (value === "") {
|
1077 |
+
return null;
|
1078 |
+
}
|
1079 |
+
|
1080 |
+
var iFormat, dim, extra,
|
1081 |
+
iValue = 0,
|
1082 |
+
shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
|
1083 |
+
shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
|
1084 |
+
new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
|
1085 |
+
dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
|
1086 |
+
dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
|
1087 |
+
monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
|
1088 |
+
monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
|
1089 |
+
year = -1,
|
1090 |
+
month = -1,
|
1091 |
+
day = -1,
|
1092 |
+
doy = -1,
|
1093 |
+
literal = false,
|
1094 |
+
date,
|
1095 |
+
// Check whether a format character is doubled
|
1096 |
+
lookAhead = function(match) {
|
1097 |
+
var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
|
1098 |
+
if (matches) {
|
1099 |
+
iFormat++;
|
1100 |
+
}
|
1101 |
+
return matches;
|
1102 |
+
},
|
1103 |
+
// Extract a number from the string value
|
1104 |
+
getNumber = function(match) {
|
1105 |
+
var isDoubled = lookAhead(match),
|
1106 |
+
size = (match === "@" ? 14 : (match === "!" ? 20 :
|
1107 |
+
(match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
|
1108 |
+
digits = new RegExp("^\\d{1," + size + "}"),
|
1109 |
+
num = value.substring(iValue).match(digits);
|
1110 |
+
if (!num) {
|
1111 |
+
throw "Missing number at position " + iValue;
|
1112 |
+
}
|
1113 |
+
iValue += num[0].length;
|
1114 |
+
return parseInt(num[0], 10);
|
1115 |
+
},
|
1116 |
+
// Extract a name from the string value and convert to an index
|
1117 |
+
getName = function(match, shortNames, longNames) {
|
1118 |
+
var index = -1,
|
1119 |
+
names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
|
1120 |
+
return [ [k, v] ];
|
1121 |
+
}).sort(function (a, b) {
|
1122 |
+
return -(a[1].length - b[1].length);
|
1123 |
+
});
|
1124 |
+
|
1125 |
+
$.each(names, function (i, pair) {
|
1126 |
+
var name = pair[1];
|
1127 |
+
if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
|
1128 |
+
index = pair[0];
|
1129 |
+
iValue += name.length;
|
1130 |
+
return false;
|
1131 |
+
}
|
1132 |
+
});
|
1133 |
+
if (index !== -1) {
|
1134 |
+
return index + 1;
|
1135 |
+
} else {
|
1136 |
+
throw "Unknown name at position " + iValue;
|
1137 |
+
}
|
1138 |
+
},
|
1139 |
+
// Confirm that a literal character matches the string value
|
1140 |
+
checkLiteral = function() {
|
1141 |
+
if (value.charAt(iValue) !== format.charAt(iFormat)) {
|
1142 |
+
throw "Unexpected literal at position " + iValue;
|
1143 |
+
}
|
1144 |
+
iValue++;
|
1145 |
+
};
|
1146 |
+
|
1147 |
+
for (iFormat = 0; iFormat < format.length; iFormat++) {
|
1148 |
+
if (literal) {
|
1149 |
+
if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
|
1150 |
+
literal = false;
|
1151 |
+
} else {
|
1152 |
+
checkLiteral();
|
1153 |
+
}
|
1154 |
+
} else {
|
1155 |
+
switch (format.charAt(iFormat)) {
|
1156 |
+
case "d":
|
1157 |
+
day = getNumber("d");
|
1158 |
+
break;
|
1159 |
+
case "D":
|
1160 |
+
getName("D", dayNamesShort, dayNames);
|
1161 |
+
break;
|
1162 |
+
case "o":
|
1163 |
+
doy = getNumber("o");
|
1164 |
+
break;
|
1165 |
+
case "m":
|
1166 |
+
month = getNumber("m");
|
1167 |
+
break;
|
1168 |
+
case "M":
|
1169 |
+
month = getName("M", monthNamesShort, monthNames);
|
1170 |
+
break;
|
1171 |
+
case "y":
|
1172 |
+
year = getNumber("y");
|
1173 |
+
break;
|
1174 |
+
case "@":
|
1175 |
+
date = new Date(getNumber("@"));
|
1176 |
+
year = date.getFullYear();
|
1177 |
+
month = date.getMonth() + 1;
|
1178 |
+
day = date.getDate();
|
1179 |
+
break;
|
1180 |
+
case "!":
|
1181 |
+
date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
|
1182 |
+
year = date.getFullYear();
|
1183 |
+
month = date.getMonth() + 1;
|
1184 |
+
day = date.getDate();
|
1185 |
+
break;
|
1186 |
+
case "'":
|
1187 |
+
if (lookAhead("'")){
|
1188 |
+
checkLiteral();
|
1189 |
+
} else {
|
1190 |
+
literal = true;
|
1191 |
+
}
|
1192 |
+
break;
|
1193 |
+
default:
|
1194 |
+
checkLiteral();
|
1195 |
+
}
|
1196 |
+
}
|
1197 |
+
}
|
1198 |
+
|
1199 |
+
if (iValue < value.length){
|
1200 |
+
extra = value.substr(iValue);
|
1201 |
+
if (!/^\s+/.test(extra)) {
|
1202 |
+
throw "Extra/unparsed characters found in date: " + extra;
|
1203 |
+
}
|
1204 |
+
}
|
1205 |
+
|
1206 |
+
if (year === -1) {
|
1207 |
+
year = new Date().getFullYear();
|
1208 |
+
} else if (year < 100) {
|
1209 |
+
year += new Date().getFullYear() - new Date().getFullYear() % 100 +
|
1210 |
+
(year <= shortYearCutoff ? 0 : -100);
|
1211 |
+
}
|
1212 |
+
|
1213 |
+
if (doy > -1) {
|
1214 |
+
month = 1;
|
1215 |
+
day = doy;
|
1216 |
+
do {
|
1217 |
+
dim = this._getDaysInMonth(year, month - 1);
|
1218 |
+
if (day <= dim) {
|
1219 |
+
break;
|
1220 |
+
}
|
1221 |
+
month++;
|
1222 |
+
day -= dim;
|
1223 |
+
} while (true);
|
1224 |
+
}
|
1225 |
+
|
1226 |
+
date = this._daylightSavingAdjust(new Date(year, month - 1, day));
|
1227 |
+
if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
|
1228 |
+
throw "Invalid date"; // E.g. 31/02/00
|
1229 |
+
}
|
1230 |
+
return date;
|
1231 |
+
},
|
1232 |
+
|
1233 |
+
/* Standard date formats. */
|
1234 |
+
ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
|
1235 |
+
COOKIE: "D, dd M yy",
|
1236 |
+
ISO_8601: "yy-mm-dd",
|
1237 |
+
RFC_822: "D, d M y",
|
1238 |
+
RFC_850: "DD, dd-M-y",
|
1239 |
+
RFC_1036: "D, d M y",
|
1240 |
+
RFC_1123: "D, d M yy",
|
1241 |
+
RFC_2822: "D, d M yy",
|
1242 |
+
RSS: "D, d M y", // RFC 822
|
1243 |
+
TICKS: "!",
|
1244 |
+
TIMESTAMP: "@",
|
1245 |
+
W3C: "yy-mm-dd", // ISO 8601
|
1246 |
+
|
1247 |
+
_ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
|
1248 |
+
Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
|
1249 |
+
|
1250 |
+
/* Format a date object into a string value.
|
1251 |
+
* The format can be combinations of the following:
|
1252 |
+
* d - day of month (no leading zero)
|
1253 |
+
* dd - day of month (two digit)
|
1254 |
+
* o - day of year (no leading zeros)
|
1255 |
+
* oo - day of year (three digit)
|
1256 |
+
* D - day name short
|
1257 |
+
* DD - day name long
|
1258 |
+
* m - month of year (no leading zero)
|
1259 |
+
* mm - month of year (two digit)
|
1260 |
+
* M - month name short
|
1261 |
+
* MM - month name long
|
1262 |
+
* y - year (two digit)
|
1263 |
+
* yy - year (four digit)
|
1264 |
+
* @ - Unix timestamp (ms since 01/01/1970)
|
1265 |
+
* ! - Windows ticks (100ns since 01/01/0001)
|
1266 |
+
* "..." - literal text
|
1267 |
+
* '' - single quote
|
1268 |
+
*
|
1269 |
+
* @param format string - the desired format of the date
|
1270 |
+
* @param date Date - the date value to format
|
1271 |
+
* @param settings Object - attributes include:
|
1272 |
+
* dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
|
1273 |
+
* dayNames string[7] - names of the days from Sunday (optional)
|
1274 |
+
* monthNamesShort string[12] - abbreviated names of the months (optional)
|
1275 |
+
* monthNames string[12] - names of the months (optional)
|
1276 |
+
* @return string - the date in the above format
|
1277 |
+
*/
|
1278 |
+
formatDate: function (format, date, settings) {
|
1279 |
+
if (!date) {
|
1280 |
+
return "";
|
1281 |
+
}
|
1282 |
+
|
1283 |
+
var iFormat,
|
1284 |
+
dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
|
1285 |
+
dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
|
1286 |
+
monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
|
1287 |
+
monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
|
1288 |
+
// Check whether a format character is doubled
|
1289 |
+
lookAhead = function(match) {
|
1290 |
+
var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
|
1291 |
+
if (matches) {
|
1292 |
+
iFormat++;
|
1293 |
+
}
|
1294 |
+
return matches;
|
1295 |
+
},
|
1296 |
+
// Format a number, with leading zero if necessary
|
1297 |
+
formatNumber = function(match, value, len) {
|
1298 |
+
var num = "" + value;
|
1299 |
+
if (lookAhead(match)) {
|
1300 |
+
while (num.length < len) {
|
1301 |
+
num = "0" + num;
|
1302 |
+
}
|
1303 |
+
}
|
1304 |
+
return num;
|
1305 |
+
},
|
1306 |
+
// Format a name, short or long as requested
|
1307 |
+
formatName = function(match, value, shortNames, longNames) {
|
1308 |
+
return (lookAhead(match) ? longNames[value] : shortNames[value]);
|
1309 |
+
},
|
1310 |
+
output = "",
|
1311 |
+
literal = false;
|
1312 |
+
|
1313 |
+
if (date) {
|
1314 |
+
for (iFormat = 0; iFormat < format.length; iFormat++) {
|
1315 |
+
if (literal) {
|
1316 |
+
if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
|
1317 |
+
literal = false;
|
1318 |
+
} else {
|
1319 |
+
output += format.charAt(iFormat);
|
1320 |
+
}
|
1321 |
+
} else {
|
1322 |
+
switch (format.charAt(iFormat)) {
|
1323 |
+
case "d":
|
1324 |
+
output += formatNumber("d", date.getDate(), 2);
|
1325 |
+
break;
|
1326 |
+
case "D":
|
1327 |
+
output += formatName("D", date.getDay(), dayNamesShort, dayNames);
|
1328 |
+
break;
|
1329 |
+
case "o":
|
1330 |
+
output += formatNumber("o",
|
1331 |
+
Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
|
1332 |
+
break;
|
1333 |
+
case "m":
|
1334 |
+
output += formatNumber("m", date.getMonth() + 1, 2);
|
1335 |
+
break;
|
1336 |
+
case "M":
|
1337 |
+
output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
|
1338 |
+
break;
|
1339 |
+
case "y":
|
1340 |
+
output += (lookAhead("y") ? date.getFullYear() :
|
1341 |
+
(date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
|
1342 |
+
break;
|
1343 |
+
case "@":
|
1344 |
+
output += date.getTime();
|
1345 |
+
break;
|
1346 |
+
case "!":
|
1347 |
+
output += date.getTime() * 10000 + this._ticksTo1970;
|
1348 |
+
break;
|
1349 |
+
case "'":
|
1350 |
+
if (lookAhead("'")) {
|
1351 |
+
output += "'";
|
1352 |
+
} else {
|
1353 |
+
literal = true;
|
1354 |
+
}
|
1355 |
+
break;
|
1356 |
+
default:
|
1357 |
+
output += format.charAt(iFormat);
|
1358 |
+
}
|
1359 |
+
}
|
1360 |
+
}
|
1361 |
+
}
|
1362 |
+
return output;
|
1363 |
+
},
|
1364 |
+
|
1365 |
+
/* Extract all possible characters from the date format. */
|
1366 |
+
_possibleChars: function (format) {
|
1367 |
+
var iFormat,
|
1368 |
+
chars = "",
|
1369 |
+
literal = false,
|
1370 |
+
// Check whether a format character is doubled
|
1371 |
+
lookAhead = function(match) {
|
1372 |
+
var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
|
1373 |
+
if (matches) {
|
1374 |
+
iFormat++;
|
1375 |
+
}
|
1376 |
+
return matches;
|
1377 |
+
};
|
1378 |
+
|
1379 |
+
for (iFormat = 0; iFormat < format.length; iFormat++) {
|
1380 |
+
if (literal) {
|
1381 |
+
if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
|
1382 |
+
literal = false;
|
1383 |
+
} else {
|
1384 |
+
chars += format.charAt(iFormat);
|
1385 |
+
}
|
1386 |
+
} else {
|
1387 |
+
switch (format.charAt(iFormat)) {
|
1388 |
+
case "d": case "m": case "y": case "@":
|
1389 |
+
chars += "0123456789";
|
1390 |
+
break;
|
1391 |
+
case "D": case "M":
|
1392 |
+
return null; // Accept anything
|
1393 |
+
case "'":
|
1394 |
+
if (lookAhead("'")) {
|
1395 |
+
chars += "'";
|
1396 |
+
} else {
|
1397 |
+
literal = true;
|
1398 |
+
}
|
1399 |
+
break;
|
1400 |
+
default:
|
1401 |
+
chars += format.charAt(iFormat);
|
1402 |
+
}
|
1403 |
+
}
|
1404 |
+
}
|
1405 |
+
return chars;
|
1406 |
+
},
|
1407 |
+
|
1408 |
+
/* Get a setting value, defaulting if necessary. */
|
1409 |
+
_get: function(inst, name) {
|
1410 |
+
return inst.settings[name] !== undefined ?
|
1411 |
+
inst.settings[name] : this._defaults[name];
|
1412 |
+
},
|
1413 |
+
|
1414 |
+
/* Parse existing date and initialise date picker. */
|
1415 |
+
_setDateFromField: function(inst, noDefault) {
|
1416 |
+
if (inst.input.val() === inst.lastVal) {
|
1417 |
+
return;
|
1418 |
+
}
|
1419 |
+
|
1420 |
+
var dateFormat = this._get(inst, "dateFormat"),
|
1421 |
+
dates = inst.lastVal = inst.input ? inst.input.val() : null,
|
1422 |
+
defaultDate = this._getDefaultDate(inst),
|
1423 |
+
date = defaultDate,
|
1424 |
+
settings = this._getFormatConfig(inst);
|
1425 |
+
|
1426 |
+
try {
|
1427 |
+
date = this.parseDate(dateFormat, dates, settings) || defaultDate;
|
1428 |
+
} catch (event) {
|
1429 |
+
dates = (noDefault ? "" : dates);
|
1430 |
+
}
|
1431 |
+
inst.selectedDay = date.getDate();
|
1432 |
+
inst.drawMonth = inst.selectedMonth = date.getMonth();
|
1433 |
+
inst.drawYear = inst.selectedYear = date.getFullYear();
|
1434 |
+
inst.currentDay = (dates ? date.getDate() : 0);
|
1435 |
+
inst.currentMonth = (dates ? date.getMonth() : 0);
|
1436 |
+
inst.currentYear = (dates ? date.getFullYear() : 0);
|
1437 |
+
this._adjustInstDate(inst);
|
1438 |
+
},
|
1439 |
+
|
1440 |
+
/* Retrieve the default date shown on opening. */
|
1441 |
+
_getDefaultDate: function(inst) {
|
1442 |
+
return this._restrictMinMax(inst,
|
1443 |
+
this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
|
1444 |
+
},
|
1445 |
+
|
1446 |
+
/* A date may be specified as an exact value or a relative one. */
|
1447 |
+
_determineDate: function(inst, date, defaultDate) {
|
1448 |
+
var offsetNumeric = function(offset) {
|
1449 |
+
var date = new Date();
|
1450 |
+
date.setDate(date.getDate() + offset);
|
1451 |
+
return date;
|
1452 |
+
},
|
1453 |
+
offsetString = function(offset) {
|
1454 |
+
try {
|
1455 |
+
return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
|
1456 |
+
offset, $.datepicker._getFormatConfig(inst));
|
1457 |
+
}
|
1458 |
+
catch (e) {
|
1459 |
+
// Ignore
|
1460 |
+
}
|
1461 |
+
|
1462 |
+
var date = (offset.toLowerCase().match(/^c/) ?
|
1463 |
+
$.datepicker._getDate(inst) : null) || new Date(),
|
1464 |
+
year = date.getFullYear(),
|
1465 |
+
month = date.getMonth(),
|
1466 |
+
day = date.getDate(),
|
1467 |
+
pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
|
1468 |
+
matches = pattern.exec(offset);
|
1469 |
+
|
1470 |
+
while (matches) {
|
1471 |
+
switch (matches[2] || "d") {
|
1472 |
+
case "d" : case "D" :
|
1473 |
+
day += parseInt(matches[1],10); break;
|
1474 |
+
case "w" : case "W" :
|
1475 |
+
day += parseInt(matches[1],10) * 7; break;
|
1476 |
+
case "m" : case "M" :
|
1477 |
+
month += parseInt(matches[1],10);
|
1478 |
+
day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
|
1479 |
+
break;
|
1480 |
+
case "y": case "Y" :
|
1481 |
+
year += parseInt(matches[1],10);
|
1482 |
+
day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
|
1483 |
+
break;
|
1484 |
+
}
|
1485 |
+
matches = pattern.exec(offset);
|
1486 |
+
}
|
1487 |
+
return new Date(year, month, day);
|
1488 |
+
},
|
1489 |
+
newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
|
1490 |
+
(typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
|
1491 |
+
|
1492 |
+
newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
|
1493 |
+
if (newDate) {
|
1494 |
+
newDate.setHours(0);
|
1495 |
+
newDate.setMinutes(0);
|
1496 |
+
newDate.setSeconds(0);
|
1497 |
+
newDate.setMilliseconds(0);
|
1498 |
+
}
|
1499 |
+
return this._daylightSavingAdjust(newDate);
|
1500 |
+
},
|
1501 |
+
|
1502 |
+
/* Handle switch to/from daylight saving.
|
1503 |
+
* Hours may be non-zero on daylight saving cut-over:
|
1504 |
+
* > 12 when midnight changeover, but then cannot generate
|
1505 |
+
* midnight datetime, so jump to 1AM, otherwise reset.
|
1506 |
+
* @param date (Date) the date to check
|
1507 |
+
* @return (Date) the corrected date
|
1508 |
+
*/
|
1509 |
+
_daylightSavingAdjust: function(date) {
|
1510 |
+
if (!date) {
|
1511 |
+
return null;
|
1512 |
+
}
|
1513 |
+
date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
|
1514 |
+
return date;
|
1515 |
+
},
|
1516 |
+
|
1517 |
+
/* Set the date(s) directly. */
|
1518 |
+
_setDate: function(inst, date, noChange) {
|
1519 |
+
var clear = !date,
|
1520 |
+
origMonth = inst.selectedMonth,
|
1521 |
+
origYear = inst.selectedYear,
|
1522 |
+
newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
|
1523 |
+
|
1524 |
+
inst.selectedDay = inst.currentDay = newDate.getDate();
|
1525 |
+
inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
|
1526 |
+
inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
|
1527 |
+
if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
|
1528 |
+
this._notifyChange(inst);
|
1529 |
+
}
|
1530 |
+
this._adjustInstDate(inst);
|
1531 |
+
if (inst.input) {
|
1532 |
+
inst.input.val(clear ? "" : this._formatDate(inst));
|
1533 |
+
}
|
1534 |
+
},
|
1535 |
+
|
1536 |
+
/* Retrieve the date(s) directly. */
|
1537 |
+
_getDate: function(inst) {
|
1538 |
+
var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
|
1539 |
+
this._daylightSavingAdjust(new Date(
|
1540 |
+
inst.currentYear, inst.currentMonth, inst.currentDay)));
|
1541 |
+
return startDate;
|
1542 |
+
},
|
1543 |
+
|
1544 |
+
/* Attach the onxxx handlers. These are declared statically so
|
1545 |
+
* they work with static code transformers like Caja.
|
1546 |
+
*/
|
1547 |
+
_attachHandlers: function(inst) {
|
1548 |
+
var stepMonths = this._get(inst, "stepMonths"),
|
1549 |
+
id = "#" + inst.id.replace( /\\\\/g, "\\" );
|
1550 |
+
inst.dpDiv.find("[data-handler]").map(function () {
|
1551 |
+
var handler = {
|
1552 |
+
prev: function () {
|
1553 |
+
$.datepicker._adjustDate(id, -stepMonths, "M");
|
1554 |
+
},
|
1555 |
+
next: function () {
|
1556 |
+
$.datepicker._adjustDate(id, +stepMonths, "M");
|
1557 |
+
},
|
1558 |
+
hide: function () {
|
1559 |
+
$.datepicker._hideDatepicker();
|
1560 |
+
},
|
1561 |
+
today: function () {
|
1562 |
+
$.datepicker._gotoToday(id);
|
1563 |
+
},
|
1564 |
+
selectDay: function () {
|
1565 |
+
$.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
|
1566 |
+
return false;
|
1567 |
+
},
|
1568 |
+
selectMonth: function () {
|
1569 |
+
$.datepicker._selectMonthYear(id, this, "M");
|
1570 |
+
return false;
|
1571 |
+
},
|
1572 |
+
selectYear: function () {
|
1573 |
+
$.datepicker._selectMonthYear(id, this, "Y");
|
1574 |
+
return false;
|
1575 |
+
}
|
1576 |
+
};
|
1577 |
+
$(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
|
1578 |
+
});
|
1579 |
+
},
|
1580 |
+
|
1581 |
+
/* Generate the HTML for the current state of the date picker. */
|
1582 |
+
_generateHTML: function(inst) {
|
1583 |
+
var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
|
1584 |
+
controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
|
1585 |
+
monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
|
1586 |
+
selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
|
1587 |
+
cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
|
1588 |
+
printDate, dRow, tbody, daySettings, otherMonth, unselectable,
|
1589 |
+
tempDate = new Date(),
|
1590 |
+
today = this._daylightSavingAdjust(
|
1591 |
+
new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
|
1592 |
+
isRTL = this._get(inst, "isRTL"),
|
1593 |
+
showButtonPanel = this._get(inst, "showButtonPanel"),
|
1594 |
+
hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
|
1595 |
+
navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
|
1596 |
+
numMonths = this._getNumberOfMonths(inst),
|
1597 |
+
showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
|
1598 |
+
stepMonths = this._get(inst, "stepMonths"),
|
1599 |
+
isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
|
1600 |
+
currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
|
1601 |
+
new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
|
1602 |
+
minDate = this._getMinMaxDate(inst, "min"),
|
1603 |
+
maxDate = this._getMinMaxDate(inst, "max"),
|
1604 |
+
drawMonth = inst.drawMonth - showCurrentAtPos,
|
1605 |
+
drawYear = inst.drawYear;
|
1606 |
+
|
1607 |
+
if (drawMonth < 0) {
|
1608 |
+
drawMonth += 12;
|
1609 |
+
drawYear--;
|
1610 |
+
}
|
1611 |
+
if (maxDate) {
|
1612 |
+
maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
|
1613 |
+
maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
|
1614 |
+
maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
|
1615 |
+
while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
|
1616 |
+
drawMonth--;
|
1617 |
+
if (drawMonth < 0) {
|
1618 |
+
drawMonth = 11;
|
1619 |
+
drawYear--;
|
1620 |
+
}
|
1621 |
+
}
|
1622 |
+
}
|
1623 |
+
inst.drawMonth = drawMonth;
|
1624 |
+
inst.drawYear = drawYear;
|
1625 |
+
|
1626 |
+
prevText = this._get(inst, "prevText");
|
1627 |
+
prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
|
1628 |
+
this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
|
1629 |
+
this._getFormatConfig(inst)));
|
1630 |
+
|
1631 |
+
prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
|
1632 |
+
"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
|
1633 |
+
" title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
|
1634 |
+
(hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>"));
|
1635 |
+
|
1636 |
+
nextText = this._get(inst, "nextText");
|
1637 |
+
nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
|
1638 |
+
this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
|
1639 |
+
this._getFormatConfig(inst)));
|
1640 |
+
|
1641 |
+
next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
|
1642 |
+
"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
|
1643 |
+
" title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
|
1644 |
+
(hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>"));
|
1645 |
+
|
1646 |
+
currentText = this._get(inst, "currentText");
|
1647 |
+
gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
|
1648 |
+
currentText = (!navigationAsDateFormat ? currentText :
|
1649 |
+
this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
|
1650 |
+
|
1651 |
+
controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
|
1652 |
+
this._get(inst, "closeText") + "</button>" : "");
|
1653 |
+
|
1654 |
+
buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
|
1655 |
+
(this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
|
1656 |
+
">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
|
1657 |
+
|
1658 |
+
firstDay = parseInt(this._get(inst, "firstDay"),10);
|
1659 |
+
firstDay = (isNaN(firstDay) ? 0 : firstDay);
|
1660 |
+
|
1661 |
+
showWeek = this._get(inst, "showWeek");
|
1662 |
+
dayNames = this._get(inst, "dayNames");
|
1663 |
+
dayNamesMin = this._get(inst, "dayNamesMin");
|
1664 |
+
monthNames = this._get(inst, "monthNames");
|
1665 |
+
monthNamesShort = this._get(inst, "monthNamesShort");
|
1666 |
+
beforeShowDay = this._get(inst, "beforeShowDay");
|
1667 |
+
showOtherMonths = this._get(inst, "showOtherMonths");
|
1668 |
+
selectOtherMonths = this._get(inst, "selectOtherMonths");
|
1669 |
+
defaultDate = this._getDefaultDate(inst);
|
1670 |
+
html = "";
|
1671 |
+
dow;
|
1672 |
+
for (row = 0; row < numMonths[0]; row++) {
|
1673 |
+
group = "";
|
1674 |
+
this.maxRows = 4;
|
1675 |
+
for (col = 0; col < numMonths[1]; col++) {
|
1676 |
+
selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
|
1677 |
+
cornerClass = " ui-corner-all";
|
1678 |
+
calender = "";
|
1679 |
+
if (isMultiMonth) {
|
1680 |
+
calender += "<div class='ui-datepicker-group";
|
1681 |
+
if (numMonths[1] > 1) {
|
1682 |
+
switch (col) {
|
1683 |
+
case 0: calender += " ui-datepicker-group-first";
|
1684 |
+
cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
|
1685 |
+
case numMonths[1]-1: calender += " ui-datepicker-group-last";
|
1686 |
+
cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
|
1687 |
+
default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
|
1688 |
+
}
|
1689 |
+
}
|
1690 |
+
calender += "'>";
|
1691 |
+
}
|
1692 |
+
calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
|
1693 |
+
(/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
|
1694 |
+
(/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
|
1695 |
+
this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
|
1696 |
+
row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
|
1697 |
+
"</div><table class='ui-datepicker-calendar'><thead>" +
|
1698 |
+
"<tr>";
|
1699 |
+
thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
|
1700 |
+
for (dow = 0; dow < 7; dow++) { // days of the week
|
1701 |
+
day = (dow + firstDay) % 7;
|
1702 |
+
thead += "<th" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
|
1703 |
+
"<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
|
1704 |
+
}
|
1705 |
+
calender += thead + "</tr></thead><tbody>";
|
1706 |
+
daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
|
1707 |
+
if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
|
1708 |
+
inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
|
1709 |
+
}
|
1710 |
+
leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
|
1711 |
+
curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
|
1712 |
+
numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
|
1713 |
+
this.maxRows = numRows;
|
1714 |
+
printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
|
1715 |
+
for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
|
1716 |
+
calender += "<tr>";
|
1717 |
+
tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
|
1718 |
+
this._get(inst, "calculateWeek")(printDate) + "</td>");
|
1719 |
+
for (dow = 0; dow < 7; dow++) { // create date picker days
|
1720 |
+
daySettings = (beforeShowDay ?
|
1721 |
+
beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
|
1722 |
+
otherMonth = (printDate.getMonth() !== drawMonth);
|
1723 |
+
unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
|
1724 |
+
(minDate && printDate < minDate) || (maxDate && printDate > maxDate);
|
1725 |
+
tbody += "<td class='" +
|
1726 |
+
((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
|
1727 |
+
(otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
|
1728 |
+
((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
|
1729 |
+
(defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
|
1730 |
+
// or defaultDate is current printedDate and defaultDate is selectedDate
|
1731 |
+
" " + this._dayOverClass : "") + // highlight selected day
|
1732 |
+
(unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
|
1733 |
+
(otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
|
1734 |
+
(printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
|
1735 |
+
(printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
|
1736 |
+
((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title
|
1737 |
+
(unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
|
1738 |
+
(otherMonth && !showOtherMonths ? " " : // display for other months
|
1739 |
+
(unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
|
1740 |
+
(printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
|
1741 |
+
(printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
|
1742 |
+
(otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
|
1743 |
+
"' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
|
1744 |
+
printDate.setDate(printDate.getDate() + 1);
|
1745 |
+
printDate = this._daylightSavingAdjust(printDate);
|
1746 |
+
}
|
1747 |
+
calender += tbody + "</tr>";
|
1748 |
+
}
|
1749 |
+
drawMonth++;
|
1750 |
+
if (drawMonth > 11) {
|
1751 |
+
drawMonth = 0;
|
1752 |
+
drawYear++;
|
1753 |
+
}
|
1754 |
+
calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
|
1755 |
+
((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
|
1756 |
+
group += calender;
|
1757 |
+
}
|
1758 |
+
html += group;
|
1759 |
+
}
|
1760 |
+
html += buttonPanel;
|
1761 |
+
inst._keyEvent = false;
|
1762 |
+
return html;
|
1763 |
+
},
|
1764 |
+
|
1765 |
+
/* Generate the month and year header. */
|
1766 |
+
_generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
|
1767 |
+
secondary, monthNames, monthNamesShort) {
|
1768 |
+
|
1769 |
+
var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
|
1770 |
+
changeMonth = this._get(inst, "changeMonth"),
|
1771 |
+
changeYear = this._get(inst, "changeYear"),
|
1772 |
+
showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
|
1773 |
+
html = "<div class='ui-datepicker-title'>",
|
1774 |
+
monthHtml = "";
|
1775 |
+
|
1776 |
+
// month selection
|
1777 |
+
if (secondary || !changeMonth) {
|
1778 |
+
monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
|
1779 |
+
} else {
|
1780 |
+
inMinYear = (minDate && minDate.getFullYear() === drawYear);
|
1781 |
+
inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
|
1782 |
+
monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
|
1783 |
+
for ( month = 0; month < 12; month++) {
|
1784 |
+
if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
|
1785 |
+
monthHtml += "<option value='" + month + "'" +
|
1786 |
+
(month === drawMonth ? " selected='selected'" : "") +
|
1787 |
+
">" + monthNamesShort[month] + "</option>";
|
1788 |
+
}
|
1789 |
+
}
|
1790 |
+
monthHtml += "</select>";
|
1791 |
+
}
|
1792 |
+
|
1793 |
+
if (!showMonthAfterYear) {
|
1794 |
+
html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : "");
|
1795 |
+
}
|
1796 |
+
|
1797 |
+
// year selection
|
1798 |
+
if ( !inst.yearshtml ) {
|
1799 |
+
inst.yearshtml = "";
|
1800 |
+
if (secondary || !changeYear) {
|
1801 |
+
html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
|
1802 |
+
} else {
|
1803 |
+
// determine range of years to display
|
1804 |
+
years = this._get(inst, "yearRange").split(":");
|
1805 |
+
thisYear = new Date().getFullYear();
|
1806 |
+
determineYear = function(value) {
|
1807 |
+
var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
|
1808 |
+
(value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
|
1809 |
+
parseInt(value, 10)));
|
1810 |
+
return (isNaN(year) ? thisYear : year);
|
1811 |
+
};
|
1812 |
+
year = determineYear(years[0]);
|
1813 |
+
endYear = Math.max(year, determineYear(years[1] || ""));
|
1814 |
+
year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
|
1815 |
+
endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
|
1816 |
+
inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
|
1817 |
+
for (; year <= endYear; year++) {
|
1818 |
+
inst.yearshtml += "<option value='" + year + "'" +
|
1819 |
+
(year === drawYear ? " selected='selected'" : "") +
|
1820 |
+
">" + year + "</option>";
|
1821 |
+
}
|
1822 |
+
inst.yearshtml += "</select>";
|
1823 |
+
|
1824 |
+
html += inst.yearshtml;
|
1825 |
+
inst.yearshtml = null;
|
1826 |
+
}
|
1827 |
+
}
|
1828 |
+
|
1829 |
+
html += this._get(inst, "yearSuffix");
|
1830 |
+
if (showMonthAfterYear) {
|
1831 |
+
html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml;
|
1832 |
+
}
|
1833 |
+
html += "</div>"; // Close datepicker_header
|
1834 |
+
return html;
|
1835 |
+
},
|
1836 |
+
|
1837 |
+
/* Adjust one of the date sub-fields. */
|
1838 |
+
_adjustInstDate: function(inst, offset, period) {
|
1839 |
+
var year = inst.drawYear + (period === "Y" ? offset : 0),
|
1840 |
+
month = inst.drawMonth + (period === "M" ? offset : 0),
|
1841 |
+
day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
|
1842 |
+
date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
|
1843 |
+
|
1844 |
+
inst.selectedDay = date.getDate();
|
1845 |
+
inst.drawMonth = inst.selectedMonth = date.getMonth();
|
1846 |
+
inst.drawYear = inst.selectedYear = date.getFullYear();
|
1847 |
+
if (period === "M" || period === "Y") {
|
1848 |
+
this._notifyChange(inst);
|
1849 |
+
}
|
1850 |
+
},
|
1851 |
+
|
1852 |
+
/* Ensure a date is within any min/max bounds. */
|
1853 |
+
_restrictMinMax: function(inst, date) {
|
1854 |
+
var minDate = this._getMinMaxDate(inst, "min"),
|
1855 |
+
maxDate = this._getMinMaxDate(inst, "max"),
|
1856 |
+
newDate = (minDate && date < minDate ? minDate : date);
|
1857 |
+
return (maxDate && newDate > maxDate ? maxDate : newDate);
|
1858 |
+
},
|
1859 |
+
|
1860 |
+
/* Notify change of month/year. */
|
1861 |
+
_notifyChange: function(inst) {
|
1862 |
+
var onChange = this._get(inst, "onChangeMonthYear");
|
1863 |
+
if (onChange) {
|
1864 |
+
onChange.apply((inst.input ? inst.input[0] : null),
|
1865 |
+
[inst.selectedYear, inst.selectedMonth + 1, inst]);
|
1866 |
+
}
|
1867 |
+
},
|
1868 |
+
|
1869 |
+
/* Determine the number of months to show. */
|
1870 |
+
_getNumberOfMonths: function(inst) {
|
1871 |
+
var numMonths = this._get(inst, "numberOfMonths");
|
1872 |
+
return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
|
1873 |
+
},
|
1874 |
+
|
1875 |
+
/* Determine the current maximum date - ensure no time components are set. */
|
1876 |
+
_getMinMaxDate: function(inst, minMax) {
|
1877 |
+
return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
|
1878 |
+
},
|
1879 |
+
|
1880 |
+
/* Find the number of days in a given month. */
|
1881 |
+
_getDaysInMonth: function(year, month) {
|
1882 |
+
return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
|
1883 |
+
},
|
1884 |
+
|
1885 |
+
/* Find the day of the week of the first of a month. */
|
1886 |
+
_getFirstDayOfMonth: function(year, month) {
|
1887 |
+
return new Date(year, month, 1).getDay();
|
1888 |
+
},
|
1889 |
+
|
1890 |
+
/* Determines if we should allow a "next/prev" month display change. */
|
1891 |
+
_canAdjustMonth: function(inst, offset, curYear, curMonth) {
|
1892 |
+
var numMonths = this._getNumberOfMonths(inst),
|
1893 |
+
date = this._daylightSavingAdjust(new Date(curYear,
|
1894 |
+
curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
|
1895 |
+
|
1896 |
+
if (offset < 0) {
|
1897 |
+
date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
|
1898 |
+
}
|
1899 |
+
return this._isInRange(inst, date);
|
1900 |
+
},
|
1901 |
+
|
1902 |
+
/* Is the given date in the accepted range? */
|
1903 |
+
_isInRange: function(inst, date) {
|
1904 |
+
var yearSplit, currentYear,
|
1905 |
+
minDate = this._getMinMaxDate(inst, "min"),
|
1906 |
+
maxDate = this._getMinMaxDate(inst, "max"),
|
1907 |
+
minYear = null,
|
1908 |
+
maxYear = null,
|
1909 |
+
years = this._get(inst, "yearRange");
|
1910 |
+
if (years){
|
1911 |
+
yearSplit = years.split(":");
|
1912 |
+
currentYear = new Date().getFullYear();
|
1913 |
+
minYear = parseInt(yearSplit[0], 10);
|
1914 |
+
maxYear = parseInt(yearSplit[1], 10);
|
1915 |
+
if ( yearSplit[0].match(/[+\-].*/) ) {
|
1916 |
+
minYear += currentYear;
|
1917 |
+
}
|
1918 |
+
if ( yearSplit[1].match(/[+\-].*/) ) {
|
1919 |
+
maxYear += currentYear;
|
1920 |
+
}
|
1921 |
+
}
|
1922 |
+
|
1923 |
+
return ((!minDate || date.getTime() >= minDate.getTime()) &&
|
1924 |
+
(!maxDate || date.getTime() <= maxDate.getTime()) &&
|
1925 |
+
(!minYear || date.getFullYear() >= minYear) &&
|
1926 |
+
(!maxYear || date.getFullYear() <= maxYear));
|
1927 |
+
},
|
1928 |
+
|
1929 |
+
/* Provide the configuration settings for formatting/parsing. */
|
1930 |
+
_getFormatConfig: function(inst) {
|
1931 |
+
var shortYearCutoff = this._get(inst, "shortYearCutoff");
|
1932 |
+
shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
|
1933 |
+
new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
|
1934 |
+
return {shortYearCutoff: shortYearCutoff,
|
1935 |
+
dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
|
1936 |
+
monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
|
1937 |
+
},
|
1938 |
+
|
1939 |
+
/* Format the given date for display. */
|
1940 |
+
_formatDate: function(inst, day, month, year) {
|
1941 |
+
if (!day) {
|
1942 |
+
inst.currentDay = inst.selectedDay;
|
1943 |
+
inst.currentMonth = inst.selectedMonth;
|
1944 |
+
inst.currentYear = inst.selectedYear;
|
1945 |
+
}
|
1946 |
+
var date = (day ? (typeof day === "object" ? day :
|
1947 |
+
this._daylightSavingAdjust(new Date(year, month, day))) :
|
1948 |
+
this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
|
1949 |
+
return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
|
1950 |
+
}
|
1951 |
+
});
|
1952 |
+
|
1953 |
+
/*
|
1954 |
+
* Bind hover events for datepicker elements.
|
1955 |
+
* Done via delegate so the binding only occurs once in the lifetime of the parent div.
|
1956 |
+
* Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
|
1957 |
+
*/
|
1958 |
+
function bindHover(dpDiv) {
|
1959 |
+
var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
|
1960 |
+
return dpDiv.delegate(selector, "mouseout", function() {
|
1961 |
+
$(this).removeClass("ui-state-hover");
|
1962 |
+
if (this.className.indexOf("ui-datepicker-prev") !== -1) {
|
1963 |
+
$(this).removeClass("ui-datepicker-prev-hover");
|
1964 |
+
}
|
1965 |
+
if (this.className.indexOf("ui-datepicker-next") !== -1) {
|
1966 |
+
$(this).removeClass("ui-datepicker-next-hover");
|
1967 |
+
}
|
1968 |
+
})
|
1969 |
+
.delegate(selector, "mouseover", function(){
|
1970 |
+
if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
|
1971 |
+
$(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
|
1972 |
+
$(this).addClass("ui-state-hover");
|
1973 |
+
if (this.className.indexOf("ui-datepicker-prev") !== -1) {
|
1974 |
+
$(this).addClass("ui-datepicker-prev-hover");
|
1975 |
+
}
|
1976 |
+
if (this.className.indexOf("ui-datepicker-next") !== -1) {
|
1977 |
+
$(this).addClass("ui-datepicker-next-hover");
|
1978 |
+
}
|
1979 |
+
}
|
1980 |
+
});
|
1981 |
+
}
|
1982 |
+
|
1983 |
+
/* jQuery extend now ignores nulls! */
|
1984 |
+
function extendRemove(target, props) {
|
1985 |
+
$.extend(target, props);
|
1986 |
+
for (var name in props) {
|
1987 |
+
if (props[name] == null) {
|
1988 |
+
target[name] = props[name];
|
1989 |
+
}
|
1990 |
+
}
|
1991 |
+
return target;
|
1992 |
+
}
|
1993 |
+
|
1994 |
+
/* Invoke the datepicker functionality.
|
1995 |
+
@param options string - a command, optionally followed by additional parameters or
|
1996 |
+
Object - settings for attaching new datepicker functionality
|
1997 |
+
@return jQuery object */
|
1998 |
+
$.fn.datepicker = function(options){
|
1999 |
+
|
2000 |
+
/* Verify an empty collection wasn't passed - Fixes #6976 */
|
2001 |
+
if ( !this.length ) {
|
2002 |
+
return this;
|
2003 |
+
}
|
2004 |
+
|
2005 |
+
/* Initialise the date picker. */
|
2006 |
+
if (!$.datepicker.initialized) {
|
2007 |
+
$(document).mousedown($.datepicker._checkExternalClick);
|
2008 |
+
$.datepicker.initialized = true;
|
2009 |
+
}
|
2010 |
+
|
2011 |
+
/* Append datepicker main container to body if not exist. */
|
2012 |
+
if ($("#"+$.datepicker._mainDivId).length === 0) {
|
2013 |
+
$("body").append($.datepicker.dpDiv);
|
2014 |
+
}
|
2015 |
+
|
2016 |
+
var otherArgs = Array.prototype.slice.call(arguments, 1);
|
2017 |
+
if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
|
2018 |
+
return $.datepicker["_" + options + "Datepicker"].
|
2019 |
+
apply($.datepicker, [this[0]].concat(otherArgs));
|
2020 |
+
}
|
2021 |
+
if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
|
2022 |
+
return $.datepicker["_" + options + "Datepicker"].
|
2023 |
+
apply($.datepicker, [this[0]].concat(otherArgs));
|
2024 |
+
}
|
2025 |
+
return this.each(function() {
|
2026 |
+
typeof options === "string" ?
|
2027 |
+
$.datepicker["_" + options + "Datepicker"].
|
2028 |
+
apply($.datepicker, [this].concat(otherArgs)) :
|
2029 |
+
$.datepicker._attachDatepicker(this, options);
|
2030 |
+
});
|
2031 |
+
};
|
2032 |
+
|
2033 |
+
$.datepicker = new Datepicker(); // singleton instance
|
2034 |
+
$.datepicker.initialized = false;
|
2035 |
+
$.datepicker.uuid = new Date().getTime();
|
2036 |
+
$.datepicker.version = "1.10.4";
|
2037 |
+
|
2038 |
+
})(jQuery);
|
lib/cmb_metaboxes/js/jquery.timePicker.min.js
CHANGED
@@ -1,13 +1,13 @@
|
|
1 |
-
/**
|
2 |
-
* A time picker for jQuery.
|
3 |
-
*
|
4 |
-
* Dual licensed under the MIT and GPL licenses.
|
5 |
-
* Copyright (c) 2009 Anders Fajerson
|
6 |
-
*
|
7 |
-
* @name timePicker
|
8 |
-
* @author Anders Fajerson (http://perifer.se)
|
9 |
-
* @see http://github.com/perifer/timePicker
|
10 |
-
* @example $("#mytime").timePicker();
|
11 |
-
* @example $("#mytime").timePicker({step:30, startTime:"15:00", endTime:"18:00"});
|
12 |
-
*/
|
13 |
(function(a){function g(a){a.setFullYear(2001),a.setMonth(0),a.setDate(0);return a}function f(a,b){if(a){var c=a.split(b.separator),d=parseFloat(c[0]),e=parseFloat(c[1]);b.show24Hours||(d===12&&a.indexOf("AM")!==-1?d=0:d!==12&&a.indexOf("PM")!==-1&&(d+=12));var f=new Date(0,0,0,d,e,0);return g(f)}return null}function e(a,b){return typeof a=="object"?g(a):f(a,b)}function d(a){return(a<10?"0":"")+a}function c(a,b){var c=a.getHours(),e=b.show24Hours?c:(c+11)%12+1,f=a.getMinutes();return d(e)+b.separator+d(f)+(b.show24Hours?"":c<12?" AM":" PM")}function b(b,c,d,e){b.value=a(c).text(),a(b).change(),a.browser.msie||b.focus(),d.hide()}a.fn.timePicker=function(b){var c=a.extend({},a.fn.timePicker.defaults,b);return this.each(function(){a.timePicker(this,c)})},a.timePicker=function(b,c){var d=a(b)[0];return d.timePicker||(d.timePicker=new jQuery._timePicker(d,c))},a.timePicker.version="0.3",a._timePicker=function(d,h){var i=!1,j=!1,k=e(h.startTime,h),l=e(h.endTime,h),m="selected",n="li."+m;a(d).attr("autocomplete","OFF");var o=[],p=new Date(k);while(p<=l)o[o.length]=c(p,h),p=new Date(p.setMinutes(p.getMinutes()+h.step));var q=a('<div class="time-picker'+(h.show24Hours?"":" time-picker-12hours")+'"></div>'),r=a("<ul></ul>");for(var s=0;s<o.length;s++)r.append("<li>"+o[s]+"</li>");q.append(r),q.appendTo("body").hide(),q.mouseover(function(){i=!0}).mouseout(function(){i=!1}),a("li",r).mouseover(function(){j||(a(n,q).removeClass(m),a(this).addClass(m))}).mousedown(function(){i=!0}).click(function(){b(d,this,q,h),i=!1});var t=function(){if(q.is(":visible"))return!1;a("li",q).removeClass(m);var b=a(d).offset();q.css({top:b.top+d.offsetHeight,left:b.left}),q.show();var e=d.value?f(d.value,h):k,i=k.getHours()*60+k.getMinutes(),j=e.getHours()*60+e.getMinutes()-i,n=Math.round(j/h.step),o=g(new Date(0,0,0,0,n*h.step+i,0));o=k<o&&o<=l?o:k;var p=a("li:contains("+c(o,h)+")",q);p.length&&(p.addClass(m),q[0].scrollTop=p[0].offsetTop);return!0};a(d).focus(t).click(t),a(d).blur(function(){i||q.hide()});var u=a.browser.opera||a.browser.mozilla?"keypress":"keydown";a(d)[u](function(c){var e;j=!0;var f=q[0].scrollTop;switch(c.keyCode){case 38:if(t())return!1;e=a(n,r);var g=e.prev().addClass(m)[0];g?(e.removeClass(m),g.offsetTop<f&&(q[0].scrollTop=f-g.offsetHeight)):(e.removeClass(m),g=a("li:last",r).addClass(m)[0],q[0].scrollTop=g.offsetTop-g.offsetHeight);return!1;case 40:if(t())return!1;e=a(n,r);var i=e.next().addClass(m)[0];i?(e.removeClass(m),i.offsetTop+i.offsetHeight>f+q[0].offsetHeight&&(q[0].scrollTop=f+i.offsetHeight)):(e.removeClass(m),i=a("li:first",r).addClass(m)[0],q[0].scrollTop=0);return!1;case 13:if(q.is(":visible")){var k=a(n,r)[0];b(d,k,q,h)}return!1;case 27:q.hide();return!1}return!0}),a(d).keyup(function(a){j=!1}),this.getTime=function(){return f(d.value,h)},this.setTime=function(b){d.value=c(e(b,h),h),a(d).change()}},a.fn.timePicker.defaults={step:30,startTime:new Date(0,0,0,0,0,0),endTime:new Date(0,0,0,23,30,0),separator:":",show24Hours:!0}})(jQuery)
|
1 |
+
/**
|
2 |
+
* A time picker for jQuery.
|
3 |
+
*
|
4 |
+
* Dual licensed under the MIT and GPL licenses.
|
5 |
+
* Copyright (c) 2009 Anders Fajerson
|
6 |
+
*
|
7 |
+
* @name timePicker
|
8 |
+
* @author Anders Fajerson (http://perifer.se)
|
9 |
+
* @see http://github.com/perifer/timePicker
|
10 |
+
* @example $("#mytime").timePicker();
|
11 |
+
* @example $("#mytime").timePicker({step:30, startTime:"15:00", endTime:"18:00"});
|
12 |
+
*/
|
13 |
(function(a){function g(a){a.setFullYear(2001),a.setMonth(0),a.setDate(0);return a}function f(a,b){if(a){var c=a.split(b.separator),d=parseFloat(c[0]),e=parseFloat(c[1]);b.show24Hours||(d===12&&a.indexOf("AM")!==-1?d=0:d!==12&&a.indexOf("PM")!==-1&&(d+=12));var f=new Date(0,0,0,d,e,0);return g(f)}return null}function e(a,b){return typeof a=="object"?g(a):f(a,b)}function d(a){return(a<10?"0":"")+a}function c(a,b){var c=a.getHours(),e=b.show24Hours?c:(c+11)%12+1,f=a.getMinutes();return d(e)+b.separator+d(f)+(b.show24Hours?"":c<12?" AM":" PM")}function b(b,c,d,e){b.value=a(c).text(),a(b).change(),a.browser.msie||b.focus(),d.hide()}a.fn.timePicker=function(b){var c=a.extend({},a.fn.timePicker.defaults,b);return this.each(function(){a.timePicker(this,c)})},a.timePicker=function(b,c){var d=a(b)[0];return d.timePicker||(d.timePicker=new jQuery._timePicker(d,c))},a.timePicker.version="0.3",a._timePicker=function(d,h){var i=!1,j=!1,k=e(h.startTime,h),l=e(h.endTime,h),m="selected",n="li."+m;a(d).attr("autocomplete","OFF");var o=[],p=new Date(k);while(p<=l)o[o.length]=c(p,h),p=new Date(p.setMinutes(p.getMinutes()+h.step));var q=a('<div class="time-picker'+(h.show24Hours?"":" time-picker-12hours")+'"></div>'),r=a("<ul></ul>");for(var s=0;s<o.length;s++)r.append("<li>"+o[s]+"</li>");q.append(r),q.appendTo("body").hide(),q.mouseover(function(){i=!0}).mouseout(function(){i=!1}),a("li",r).mouseover(function(){j||(a(n,q).removeClass(m),a(this).addClass(m))}).mousedown(function(){i=!0}).click(function(){b(d,this,q,h),i=!1});var t=function(){if(q.is(":visible"))return!1;a("li",q).removeClass(m);var b=a(d).offset();q.css({top:b.top+d.offsetHeight,left:b.left}),q.show();var e=d.value?f(d.value,h):k,i=k.getHours()*60+k.getMinutes(),j=e.getHours()*60+e.getMinutes()-i,n=Math.round(j/h.step),o=g(new Date(0,0,0,0,n*h.step+i,0));o=k<o&&o<=l?o:k;var p=a("li:contains("+c(o,h)+")",q);p.length&&(p.addClass(m),q[0].scrollTop=p[0].offsetTop);return!0};a(d).focus(t).click(t),a(d).blur(function(){i||q.hide()});var u=a.browser.opera||a.browser.mozilla?"keypress":"keydown";a(d)[u](function(c){var e;j=!0;var f=q[0].scrollTop;switch(c.keyCode){case 38:if(t())return!1;e=a(n,r);var g=e.prev().addClass(m)[0];g?(e.removeClass(m),g.offsetTop<f&&(q[0].scrollTop=f-g.offsetHeight)):(e.removeClass(m),g=a("li:last",r).addClass(m)[0],q[0].scrollTop=g.offsetTop-g.offsetHeight);return!1;case 40:if(t())return!1;e=a(n,r);var i=e.next().addClass(m)[0];i?(e.removeClass(m),i.offsetTop+i.offsetHeight>f+q[0].offsetHeight&&(q[0].scrollTop=f+i.offsetHeight)):(e.removeClass(m),i=a("li:first",r).addClass(m)[0],q[0].scrollTop=0);return!1;case 13:if(q.is(":visible")){var k=a(n,r)[0];b(d,k,q,h)}return!1;case 27:q.hide();return!1}return!0}),a(d).keyup(function(a){j=!1}),this.getTime=function(){return f(d.value,h)},this.setTime=function(b){d.value=c(e(b,h),h),a(d).change()}},a.fn.timePicker.defaults={step:30,startTime:new Date(0,0,0,0,0,0),endTime:new Date(0,0,0,23,30,0),separator:":",show24Hours:!0}})(jQuery)
|
lib/cmb_metaboxes/readme.md
CHANGED
@@ -1,296 +1,296 @@
|
|
1 |
-
# Custom Metaboxes and Fields for WordPress
|
2 |
-
|
3 |
-
**Contributors**:
|
4 |
-
|
5 |
-
* WebDevStudios ( [@webdevstudios](http://twitter.com/webdevstudios ) / [webdevstudios.com](http://webdevstudios.com) )
|
6 |
-
* Justin Sternberg ( [@jtsternberg](http://twitter.com/jtsternberg ) / [webdevstudios.com](http://webdevstudios.com) )
|
7 |
-
* Jared Atchison ( [@jaredatch](http://twitter.com/jaredatch ) / [jaredatchison.com](http://jaredatchison.com/) )
|
8 |
-
* Bill Erickson ( [@billerickson](http://twitter.com/billerickson ) / [billerickson.net](http://billerickson.net/) )
|
9 |
-
* Andrew Norcross ( [@norcross](http://twitter.com/norcross ) / [andrewnorcross.com](http://andrewnorcross.com/) )
|
10 |
-
|
11 |
-
**Version**: 1.2.0
|
12 |
-
**Requires at least**: 3.5
|
13 |
-
**Tested up to**: 3.9
|
14 |
-
**License**: GPLv2
|
15 |
-
|
16 |
-
## Description
|
17 |
-
|
18 |
-
Custom Metaboxes and Fields (CMB for short) will create metaboxes and forms with custom fields that will blow your mind.
|
19 |
-
|
20 |
-
##### Features:
|
21 |
-
|
22 |
-
* Create metaboxes to be used on post edit screens.
|
23 |
-
* Create forms to be used on options pages.
|
24 |
-
* Create forms to handle user meta and display them on user profile add/edit pages.
|
25 |
-
* Flexible API that allows you to use CMB forms almost anywhere, even on the front-end.
|
26 |
-
* Several field types are included and are [listed below](#field-types).
|
27 |
-
* Custom API hook that allows you to create your own field types.
|
28 |
-
* There are numerous hooks and filters, allowing you to modify many aspects of the library (without editing it directly).
|
29 |
-
* Repeatable fields for most field types are supported, as well as repeatable field groups.
|
30 |
-
|
31 |
-
##### Field Types:
|
32 |
-
1. [`title`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#title) An arbitrary title field *
|
33 |
-
1. [`text`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text)
|
34 |
-
1. [`text_small`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_small)
|
35 |
-
1. [`text_medium`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_medium)
|
36 |
-
1. [`text_email`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_email)
|
37 |
-
1. [`text_url`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_url)
|
38 |
-
1. [`text_money`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_money)
|
39 |
-
1. [`textarea`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#textarea)
|
40 |
-
1. [`textarea_small`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#textarea_small)
|
41 |
-
1. [`textarea_code`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#textarea_code)
|
42 |
-
1. [`text_date`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_date) Date Picker
|
43 |
-
1. [`text_time`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_time) Time picker
|
44 |
-
1. [`select_timezone`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#select_timezone) Time zone dropdown
|
45 |
-
1. [`text_date_timestamp`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_date_timestamp) Date Picker (UNIX timestamp)
|
46 |
-
1. [`text_datetime_timestamp`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_datetime_timestamp) Test Date/Time Picker Combo (UNIX timestamp)
|
47 |
-
1. [`text_datetime_timestamp_timezone`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_datetime_timestamp_timezone) Test Date/Time Picker/Time zone Combo (serialized DateTime object)
|
48 |
-
1. [`colorpicker`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#colorpicker) Color picker
|
49 |
-
1. [`radio`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#radio) *
|
50 |
-
1. [`radio_inline`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#radio_inline) *
|
51 |
-
1. [`taxonomy_radio`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#taxonomy_radio) *
|
52 |
-
1. [`taxonomy_radio_inline`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#taxonomy_radio_inline) *
|
53 |
-
1. [`select`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#select)
|
54 |
-
1. [`taxonomy_select`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#taxonomy_select) *
|
55 |
-
1. [`checkbox`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#checkbox) *
|
56 |
-
1. [`multicheck`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#multicheck)
|
57 |
-
1. [`taxonomy_multicheck`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#taxonomy_multicheck) *
|
58 |
-
1. [`taxonomy_multicheck_inline`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#taxonomy_multicheck_inline)
|
59 |
-
1. [`wysiwyg`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#wysiwyg) (TinyMCE) *
|
60 |
-
1. [`file`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#file) Image/File upload *†
|
61 |
-
1. [`file_list`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#file_list) Image/File list upload
|
62 |
-
1. [`oembed`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#oembed) Converts oembed urls (instagram, twitter, youtube, etc. [oEmbed in the Codex](https://codex.wordpress.org/Embeds))
|
63 |
-
1. [`group`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#group) Hybrid field that supports adding other fields as a repeatable group. *
|
64 |
-
1. [Create your own custom field type](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#Custom)
|
65 |
-
|
66 |
-
\* Not available as a repeatable field
|
67 |
-
† Use `file_list` for repeatable
|
68 |
-
|
69 |
-
[More on field types (GitHub wiki)](https://github.com/webdevstudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types)
|
70 |
-
|
71 |
-
##### 3rd Party Resources
|
72 |
-
* [CMB Attached Posts Field](https://github.com/coreymcollins/cmb-attached-posts) from [coreymcollins](https://github.com/coreymcollins): Custom field type for attaching posts to a page.
|
73 |
-
* [CMB Field Type: Google Maps](https://github.com/mustardBees/cmb_field_map) from [mustardBees](https://github.com/mustardBees): Custom field type for Google Maps.
|
74 |
-
> The `pw_map` field stores the latitude/longitude values which you can then use to display a map in your theme.
|
75 |
-
* [CMB Field Type: Select2](https://github.com/mustardBees/cmb-field-select2) from [mustardBees](https://github.com/mustardBees): Custom field types which use the [Select2](http://ivaynberg.github.io/select2/) script:
|
76 |
-
|
77 |
-
> 1. The `pw_select field` acts much like the default select field. However, it adds typeahead-style search allowing you to quickly make a selection from a large list
|
78 |
-
> 2. The `pw_multiselect` field allows you to select multiple values with typeahead-style search. The values can be dragged and dropped to reorder
|
79 |
-
* [Taxonomy_MetaData](https://github.com/jtsternberg/Taxonomy_MetaData#to-use-taxonomy_metadata-with-custom-metaboxes-and-fields): WordPress Helper Class for saving pseudo-metadata for taxonomy terms. Includes an extended class for using CMB to generate the actual form fields.
|
80 |
-
|
81 |
-
##### Contribution
|
82 |
-
All contributions welcome. If you would like to submit a pull request, please check out the [trunk branch](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/tree/trunk) and pull request against it.
|
83 |
-
|
84 |
-
##### Links
|
85 |
-
* [Github project page](https://github.com/webdevstudios/Custom-Metaboxes-and-Fields-for-WordPress)
|
86 |
-
* [Documentation (GitHub wiki)](https://github.com/webdevstudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki)
|
87 |
-
|
88 |
-
|
89 |
-
## Installation
|
90 |
-
|
91 |
-
1. Place the CMB directory inside of your theme or plugin.
|
92 |
-
2. Copy (and rename if desired) `example-functions.php` into a folder *above* the CMB directory OR copy the entirety of its contents to your theme's `functions.php` file.
|
93 |
-
2. Edit to only include the fields you need and rename the functions (CMB directory should be left unedited in order to easily update the library).
|
94 |
-
4. Profit.
|
95 |
-
|
96 |
-
## Changelog
|
97 |
-
|
98 |
-
### 1.2.0
|
99 |
-
|
100 |
-
**Enhancements**
|
101 |
-
|
102 |
-
* Add support for custom date/time formats. Props [@Scrent](https://github.com/Scrent). ([#506](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/506))
|
103 |
-
* Simplify `wysiwyg` escaping and allow it to be overridden via the `escape_cb` parameter. ([#491](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/491))
|
104 |
-
* Add a 'Select/Deselect all' button for the `multicheck` field type.
|
105 |
-
* Add title option for [repeatable groups](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#group). Title field takes an optional replacement hash, "{#}" that will be replaced by the row number.
|
106 |
-
* New field parameter, `show_on_cb`, allows you to conditionally display a field via a callback. ([#47](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/47))
|
107 |
-
* Unit testing (the beginning). Props [@brichards](https://github.com/brichards) and [@camdensegal](https://github.com/camdensegal).
|
108 |
-
|
109 |
-
**Bug Fixes**
|
110 |
-
|
111 |
-
* Fixed issue where remove file button wouldn't clear the url field. ([#514](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/514))
|
112 |
-
* `wysiwyg` fields now allow underscores. Fixes some wysiwyg display issues in WordPress 3.8. Props [@lswilson](https://github.com/lswilson). ([#491](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/491))
|
113 |
-
* Nonce field should only be added once per page. ([#521](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/521))
|
114 |
-
* Fix `in_array` issue when a post does not have any saved terms for a taxonomy multicheck. ([#527](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/527))
|
115 |
-
* Fixed error: 'Uninitialized string offset: 0 in cmb_Meta_Box_field.php...`. Props [@DevinWalker](https://github.com/DevinWalker). ([#539](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/539), [#549](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/549)))
|
116 |
-
* Fix missing `file` field description. ([#543](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/543), [#547](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/547))
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
### 1.1.3
|
121 |
-
**Bug Fixes**
|
122 |
-
|
123 |
-
* Update `cmb_get_field_value` function as it was passing the parameters to `cmb_get_field` in the wrong order.
|
124 |
-
* Fix repeating fields not working correctly if meta key or prefix contained an integer. ([#503](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/503))
|
125 |
-
|
126 |
-
### 1.1.2
|
127 |
-
|
128 |
-
**Bug Fixes**
|
129 |
-
|
130 |
-
* Fix issue with `cmb_Meta_Box_types.php` calling a missing method, `image_id_from_url`. ([#502](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/502))
|
131 |
-
|
132 |
-
|
133 |
-
### 1.1.1
|
134 |
-
|
135 |
-
**Bug Fixes**
|
136 |
-
|
137 |
-
* Radio button values were not showing saved value. ([#500](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/500))
|
138 |
-
|
139 |
-
### 1.1.0
|
140 |
-
|
141 |
-
**Enhancements**
|
142 |
-
|
143 |
-
* [Repeatable groups](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#group)
|
144 |
-
* Support for more fields to be repeatable, including oEmbed field, and date, time, and color picker fields, etc.
|
145 |
-
* Codebase has been revamped to be more modular and object-oriented.
|
146 |
-
* New filter, `"cmb_{$element}_attributes" ` for modifying an element's attributes.
|
147 |
-
* Every field now supports an `attributes` parameter that takes an array of attributes. [Read more](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#attributes).
|
148 |
-
* Removed `cmb_std_filter` in favor of `cmb_default_filter`. **THIS IS A BREAKING CHANGE**
|
149 |
-
* Better handling of labels in sidebar. They are now placed on top of the input rather than adjacent.
|
150 |
-
* Added i18n compatibility to text_money. props [@ArchCarrier](https://github.com/ArchCarrier), ([#485](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/485))
|
151 |
-
* New helper functions: `cmb_get_field` and `cmb_get_field_value` for getting access to CMB's field object and/or value.
|
152 |
-
* New JavaScript events, `cmb_add_row` and `cmb_remove_row` for hooking in and manipulating the new row's data.
|
153 |
-
* New filter, `cmb_localized_data`, for modifiying localized data passed to the CMB JS.
|
154 |
-
|
155 |
-
**Bug Fixes**
|
156 |
-
* Resolved occasional issue where only the first character of the label/value was diplayed. props [@mustardBees](https://github.com/mustardBees), ([#486](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/486))
|
157 |
-
|
158 |
-
|
159 |
-
### 1.0.2
|
160 |
-
|
161 |
-
**Enhancements**
|
162 |
-
|
163 |
-
* Change the way the `'cmb_validate_{$field['type']}'` filter works.
|
164 |
-
It is now passed a null value vs saved value. If null is returned, default sanitization will follow. **THIS IS A BREAKING CHANGE**. If you're already using this filter, take note.
|
165 |
-
* All field types that take an option array have been simplified to take `key => value` pairs (vs `array( 'name' => 'value', 'value' => 'key', )`). This effects the 'select', 'radio', 'radio_inline' field types. The 'multicheck' field type was already using the `key => value` format. Backwards compatibility has been maintained for those using the older style.
|
166 |
-
* Added default value option for `taxonomy_select` field type. props [@darlantc](https://github.com/darlantc), ([#473](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/473))
|
167 |
-
* Added `preview_size` parameter for `file_list` field type. props [@IgorCode](https://github.com/IgorCode), ([#471](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/471))
|
168 |
-
* Updated `file_list` images to be displayed horizontally instead of vertically. props [@IgorCode](https://github.com/IgorCode), ([#467](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/467))
|
169 |
-
* Use `get_the_terms` where possible since the data is cached.
|
170 |
-
|
171 |
-
**Bug Fixes**
|
172 |
-
|
173 |
-
* Fixed wysiwyg escaping slashes. props [@gregrickaby](https://github.com/gregrickaby), ([#465](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/465))
|
174 |
-
* Replaced `__DIR__`, as `dirname( __FILE__ )` is easier to maintain back-compatibility.
|
175 |
-
* Fixed missing table styling on new posts. props [@mustardBees](https://github.com/mustardBees), ([#438](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/438))
|
176 |
-
* Fix undeclared JS variable. [@veelen](https://github.com/veelen), ([#451](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/451))
|
177 |
-
* Fix `file_list` errors when removing all files and saving.
|
178 |
-
* Set correct `object_id` to be used later in `cmb_show_on` filter. [@lauravaq](https://github.com/lauravaq), ([#445](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/445))
|
179 |
-
* Fix sanitization recursion memeory issues.
|
180 |
-
|
181 |
-
### 1.0.1
|
182 |
-
|
183 |
-
**Enhancements**
|
184 |
-
|
185 |
-
* Now works with option pages and site settings. ([view example in wiki](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Using-CMB-to-create-an-Admin-Theme-Options-Page))
|
186 |
-
* two filters to override the setting and getting of options, `cmb_override_option_get_$option_key` and `cmb_override_option_save_$option_key` respectively. Handy for using plugins like [WP Large Options](https://github.com/voceconnect/wp-large-options/) ([also here](http://vip.wordpress.com/plugins/wp-large-options/)).
|
187 |
-
* Improved styling on taxonomy (\*tease\*) and options pages and for new 3.8 admin UI.
|
188 |
-
* New sanitization class to sanitize data when saved.
|
189 |
-
* New callback field parameter, `sanitization_cb`, for performing your own sanitization.
|
190 |
-
* new `cmb_Meta_Box_types::esc()` method that handles escaping data for display.
|
191 |
-
* New callback field parameter, `escape_cb`, for performing your own data escaping, as well as a new filter, `'cmb_types_esc_'. $field['type']`.
|
192 |
-
|
193 |
-
**Bug Fixes**
|
194 |
-
|
195 |
-
* Fixed wysiwyg editor button padding. props [@corvannoorloos](https://github.com/corvannoorloos), ([#391](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/391))
|
196 |
-
* A few php < 5.3 errors were addressed.
|
197 |
-
* Fields with quotation marks no longer break the input/textarea fields.
|
198 |
-
* metaboxes for Attachment pages now save correctly. Thanks [@nciske](https://github.com/nciske) for reporting. ([#412](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/412))
|
199 |
-
* Occasionally fields wouldn't save because of the admin show_on filter.
|
200 |
-
* Smaller images loaded to the file field type will no longer be blown up larger than their dimensions.
|
201 |
-
|
202 |
-
### 1.0.0
|
203 |
-
* Added `text_datetime_timestamp_timezone` type, a datetime combo field with an additional timezone drop down, props [@dessibelle](https://github.com/dessibelle)
|
204 |
-
* Added `select_timezone` type, a standalone time zone select dropdown. The time zone select can be used with standalone `text_datetime_timestamp` if desired. Props [@dessibelle](https://github.com/dessibelle)
|
205 |
-
* Added `text_url` type, a basic url field. Props [@dessibelle](https://github.com/dessibelle)
|
206 |
-
* Added `text_email` type, a basic email field. Props [@dessibelle](https://github.com/dessibelle)
|
207 |
-
* Added ability to display metabox fields in frontend. Default is true, but can be overriden using the `cmb_allow_frontend filter`. If set to true, an entire metabox form can be output with the `cmb_metabox_form( $meta_box, $object_id, $echo )` function. Props [@dessibelle](https://github.com/dessibelle), [@messenlehner](https://github.com/messenlehner) & [@jtsternberg](https://github.com/jtsternberg).
|
208 |
-
* Added hook `cmb_after_table` after all metabox output. Props [@wpsmith](https://github.com/wpsmith)
|
209 |
-
* `file_list` now works like a repeatable field. Add as many files as you want. Props [@coreymcollins](https://github.com/coreymcollins)
|
210 |
-
* `text`, `text_small`, `text_medium`, `text_url`, `text_email`, & `text_money` fields now all have the option to be repeatable. Props [@jtsternberg](https://github.com/jtsternberg)
|
211 |
-
* Custom metaboxes can now be added for user meta. Add them on the user add/edit screen, or in a custom user profile edit page on the front-end. Props [@tw2113](https://github.com/tw2113), [@jtsternberg](https://github.com/jtsternberg)
|
212 |
-
|
213 |
-
### 0.9.4
|
214 |
-
* Added field "before" and "after" options for each field. Solves issue with '$' not being the desired text_money monetary symbol, props [@GaryJones](https://github.com/GaryJones)
|
215 |
-
* Added filter for 'std' default fallback value, props [@messenlehner](https://github.com/messenlehner)
|
216 |
-
* Ensure oEmbed videos fit in their respective metaboxes, props [@jtsternberg](https://github.com/jtsternberg)
|
217 |
-
* Fixed issue where an upload field with 'show_names' disabled wouldn't have the correct button label, props [@jtsternberg](https://github.com/jtsternberg)
|
218 |
-
* Better file-extension check for images, props [@GhostToast](https://github.com/GhostToast)
|
219 |
-
* New filter, `cmb_valid_img_types`, for whitelisted image file-extensions, props [@jtsternberg](https://github.com/jtsternberg)
|
220 |
-
|
221 |
-
### 0.9.3
|
222 |
-
* Added field type and field id classes to each cmb table row, props [@jtsternberg](https://github.com/jtsternberg)
|
223 |
-
|
224 |
-
### 0.9.2
|
225 |
-
* Added post type comparison to prevent storing null values for taxonomy selectors, props [@norcross](https://github.com/norcross)
|
226 |
-
|
227 |
-
### 0.9.1
|
228 |
-
* Added `oEmbed` field type with ajax display, props [@jtsternberg](https://github.com/jtsternberg)
|
229 |
-
|
230 |
-
### 0.9
|
231 |
-
* __Note: This release requires WordPress 3.3+__
|
232 |
-
* Cleaned up scripts being queued, props [@jaredatch](https://github.com/jaredatch)
|
233 |
-
* Cleaned up and reorganized jQuery, props [@GaryJones](https://github.com/GaryJones)
|
234 |
-
* Use $pagenow instead of custom $current_page, props [@jaredatch](https://github.com/jaredatch)
|
235 |
-
* Fixed CSS, removed inline styles, now all in style.css, props [@jaredatch](https://github.com/jaredatch)
|
236 |
-
* Fixed multicheck issues (issue #48), props [@jaredatch](https://github.com/jaredatch)
|
237 |
-
* Fixed jQuery UI datepicker CSS conflicting with WordPress UI elements, props [@jaredatch](https://github.com/jaredatch)
|
238 |
-
* Fixed zeros not saving in fields, props [@GaryJones](https://github.com/GaryJones)
|
239 |
-
* Fixed improper labels on radio and multicheck fields, props [@jaredatch](https://github.com/jaredatch)
|
240 |
-
* Fixed fields not rendering properly when in sidebar, props [@jaredatch](https://github.com/jaredatch)
|
241 |
-
* Fixed bug where datepicker triggers extra space after footer in Firefox (issue #14), props [@jaredatch](https://github.com/jaredatch)
|
242 |
-
* Added jQuery UI datepicker packaged with 3.3 core, props [@jaredatch](https://github.com/jaredatch)
|
243 |
-
* Added date time combo picker, props [@jaredatch](https://github.com/jaredatch)
|
244 |
-
* Added color picker, props [@jaredatch](https://github.com/jaredatch)
|
245 |
-
* Added readme.md markdown file, props [@jaredatch](https://github.com/jaredatch)
|
246 |
-
|
247 |
-
### 0.8
|
248 |
-
* Added jQuery timepicker, props [@norcross](https://github.com/norcross)
|
249 |
-
* Added 'raw' textarea to convert special HTML entities back to characters, props [@norcross](https://github.com/norcross)
|
250 |
-
* Added missing examples on example-functions.php, props [@norcross](https://github.com/norcross)
|
251 |
-
|
252 |
-
### 0.7
|
253 |
-
* Added the new wp_editor() function for the WYSIWYG dialog box, props [@jcpry](https://github.com/jcpry)
|
254 |
-
* Created 'cmb_show_on' filter to define your own Show On Filters, props [@billerickson](https://github.com/billerickson)
|
255 |
-
* Added page template show_on filter, props [@billerickson](https://github.com/billerickson)
|
256 |
-
* Improvements to the 'file' field type, props [@randyhoyt](https://github.com/randyhoyt)
|
257 |
-
* Allow for default values on 'radio' and 'radio_inline' field types, props [@billerickson](https://github.com/billerickson)
|
258 |
-
|
259 |
-
### 0.6.1
|
260 |
-
* Enabled the ability to define your own custom field types (issue #28). props [@randyhoyt](https://github.com/randyhoyt)
|
261 |
-
|
262 |
-
### 0.6
|
263 |
-
* Added the ability to limit metaboxes to certain posts by id. props [@billerickson](https://github.com/billerickson)
|
264 |
-
|
265 |
-
### 0.5
|
266 |
-
* Fixed define to prevent notices. props [@destos](https://github.com/destos)
|
267 |
-
* Added text_date_timestap option. props [@andrewyno](https://github.com/andrewyno)
|
268 |
-
* Fixed WYSIWYG paragraph breaking/spacing bug. props [@wpsmith](https://github.com/wpsmith)
|
269 |
-
* Added taxonomy_radio and taxonomies_select options. props [@c3mdigital](https://github.com/c3mdigital)
|
270 |
-
* Fixed script causing the dashboard widgets to not be collapsible.
|
271 |
-
* Fixed various spacing and whitespace inconsistencies
|
272 |
-
|
273 |
-
### 0.4
|
274 |
-
* Think we have a release that is mostly working. We'll say the initial release :)
|
275 |
-
|
276 |
-
## Known Issues
|
277 |
-
|
278 |
-
* Problem inserting file url inside field for image with caption (issue #50) May be fixed, needs testing.
|
279 |
-
* `CMB_META_BOX_URL` does not define properly in WAMP/XAMP (Windows) (issue #31) May be fixed, needs testing.
|
280 |
-
* Metabox containing WYSIWYG editor cannot be moved (this is a TinyMCE issue)
|
281 |
-
|
282 |
-
## To-do
|
283 |
-
**Enhancements**
|
284 |
-
|
285 |
-
* Fix known issues (above)
|
286 |
-
* move timepicker and datepicker jQuery inline
|
287 |
-
* support for multiple configurable timepickers/datepickers
|
288 |
-
* add ability to save fields in a single custom field
|
289 |
-
* add ability to mark fields as required
|
290 |
-
* repeatable fields (halfway there)
|
291 |
-
* look at possiblity of tabs
|
292 |
-
* look at preserving taxonomy hierarchies
|
293 |
-
* Add input attributes filter
|
294 |
-
* Always load newest version of CMB
|
295 |
-
* Helper function to easily get oembed from stored oEmbed field
|
296 |
-
|
1 |
+
# Custom Metaboxes and Fields for WordPress
|
2 |
+
|
3 |
+
**Contributors**:
|
4 |
+
|
5 |
+
* WebDevStudios ( [@webdevstudios](http://twitter.com/webdevstudios ) / [webdevstudios.com](http://webdevstudios.com) )
|
6 |
+
* Justin Sternberg ( [@jtsternberg](http://twitter.com/jtsternberg ) / [webdevstudios.com](http://webdevstudios.com) )
|
7 |
+
* Jared Atchison ( [@jaredatch](http://twitter.com/jaredatch ) / [jaredatchison.com](http://jaredatchison.com/) )
|
8 |
+
* Bill Erickson ( [@billerickson](http://twitter.com/billerickson ) / [billerickson.net](http://billerickson.net/) )
|
9 |
+
* Andrew Norcross ( [@norcross](http://twitter.com/norcross ) / [andrewnorcross.com](http://andrewnorcross.com/) )
|
10 |
+
|
11 |
+
**Version**: 1.2.0
|
12 |
+
**Requires at least**: 3.5
|
13 |
+
**Tested up to**: 3.9
|
14 |
+
**License**: GPLv2
|
15 |
+
|
16 |
+
## Description
|
17 |
+
|
18 |
+
Custom Metaboxes and Fields (CMB for short) will create metaboxes and forms with custom fields that will blow your mind.
|
19 |
+
|
20 |
+
##### Features:
|
21 |
+
|
22 |
+
* Create metaboxes to be used on post edit screens.
|
23 |
+
* Create forms to be used on options pages.
|
24 |
+
* Create forms to handle user meta and display them on user profile add/edit pages.
|
25 |
+
* Flexible API that allows you to use CMB forms almost anywhere, even on the front-end.
|
26 |
+
* Several field types are included and are [listed below](#field-types).
|
27 |
+
* Custom API hook that allows you to create your own field types.
|
28 |
+
* There are numerous hooks and filters, allowing you to modify many aspects of the library (without editing it directly).
|
29 |
+
* Repeatable fields for most field types are supported, as well as repeatable field groups.
|
30 |
+
|
31 |
+
##### Field Types:
|
32 |
+
1. [`title`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#title) An arbitrary title field *
|
33 |
+
1. [`text`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text)
|
34 |
+
1. [`text_small`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_small)
|
35 |
+
1. [`text_medium`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_medium)
|
36 |
+
1. [`text_email`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_email)
|
37 |
+
1. [`text_url`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_url)
|
38 |
+
1. [`text_money`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_money)
|
39 |
+
1. [`textarea`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#textarea)
|
40 |
+
1. [`textarea_small`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#textarea_small)
|
41 |
+
1. [`textarea_code`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#textarea_code)
|
42 |
+
1. [`text_date`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_date) Date Picker
|
43 |
+
1. [`text_time`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_time) Time picker
|
44 |
+
1. [`select_timezone`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#select_timezone) Time zone dropdown
|
45 |
+
1. [`text_date_timestamp`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_date_timestamp) Date Picker (UNIX timestamp)
|
46 |
+
1. [`text_datetime_timestamp`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_datetime_timestamp) Test Date/Time Picker Combo (UNIX timestamp)
|
47 |
+
1. [`text_datetime_timestamp_timezone`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#text_datetime_timestamp_timezone) Test Date/Time Picker/Time zone Combo (serialized DateTime object)
|
48 |
+
1. [`colorpicker`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#colorpicker) Color picker
|
49 |
+
1. [`radio`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#radio) *
|
50 |
+
1. [`radio_inline`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#radio_inline) *
|
51 |
+
1. [`taxonomy_radio`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#taxonomy_radio) *
|
52 |
+
1. [`taxonomy_radio_inline`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#taxonomy_radio_inline) *
|
53 |
+
1. [`select`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#select)
|
54 |
+
1. [`taxonomy_select`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#taxonomy_select) *
|
55 |
+
1. [`checkbox`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#checkbox) *
|
56 |
+
1. [`multicheck`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#multicheck)
|
57 |
+
1. [`taxonomy_multicheck`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#taxonomy_multicheck) *
|
58 |
+
1. [`taxonomy_multicheck_inline`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#taxonomy_multicheck_inline)
|
59 |
+
1. [`wysiwyg`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#wysiwyg) (TinyMCE) *
|
60 |
+
1. [`file`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#file) Image/File upload *†
|
61 |
+
1. [`file_list`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#file_list) Image/File list upload
|
62 |
+
1. [`oembed`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#oembed) Converts oembed urls (instagram, twitter, youtube, etc. [oEmbed in the Codex](https://codex.wordpress.org/Embeds))
|
63 |
+
1. [`group`](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#group) Hybrid field that supports adding other fields as a repeatable group. *
|
64 |
+
1. [Create your own custom field type](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#Custom)
|
65 |
+
|
66 |
+
\* Not available as a repeatable field
|
67 |
+
† Use `file_list` for repeatable
|
68 |
+
|
69 |
+
[More on field types (GitHub wiki)](https://github.com/webdevstudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types)
|
70 |
+
|
71 |
+
##### 3rd Party Resources
|
72 |
+
* [CMB Attached Posts Field](https://github.com/coreymcollins/cmb-attached-posts) from [coreymcollins](https://github.com/coreymcollins): Custom field type for attaching posts to a page.
|
73 |
+
* [CMB Field Type: Google Maps](https://github.com/mustardBees/cmb_field_map) from [mustardBees](https://github.com/mustardBees): Custom field type for Google Maps.
|
74 |
+
> The `pw_map` field stores the latitude/longitude values which you can then use to display a map in your theme.
|
75 |
+
* [CMB Field Type: Select2](https://github.com/mustardBees/cmb-field-select2) from [mustardBees](https://github.com/mustardBees): Custom field types which use the [Select2](http://ivaynberg.github.io/select2/) script:
|
76 |
+
|
77 |
+
> 1. The `pw_select field` acts much like the default select field. However, it adds typeahead-style search allowing you to quickly make a selection from a large list
|
78 |
+
> 2. The `pw_multiselect` field allows you to select multiple values with typeahead-style search. The values can be dragged and dropped to reorder
|
79 |
+
* [Taxonomy_MetaData](https://github.com/jtsternberg/Taxonomy_MetaData#to-use-taxonomy_metadata-with-custom-metaboxes-and-fields): WordPress Helper Class for saving pseudo-metadata for taxonomy terms. Includes an extended class for using CMB to generate the actual form fields.
|
80 |
+
|
81 |
+
##### Contribution
|
82 |
+
All contributions welcome. If you would like to submit a pull request, please check out the [trunk branch](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/tree/trunk) and pull request against it.
|
83 |
+
|
84 |
+
##### Links
|
85 |
+
* [Github project page](https://github.com/webdevstudios/Custom-Metaboxes-and-Fields-for-WordPress)
|
86 |
+
* [Documentation (GitHub wiki)](https://github.com/webdevstudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki)
|
87 |
+
|
88 |
+
|
89 |
+
## Installation
|
90 |
+
|
91 |
+
1. Place the CMB directory inside of your theme or plugin.
|
92 |
+
2. Copy (and rename if desired) `example-functions.php` into a folder *above* the CMB directory OR copy the entirety of its contents to your theme's `functions.php` file.
|
93 |
+
2. Edit to only include the fields you need and rename the functions (CMB directory should be left unedited in order to easily update the library).
|
94 |
+
4. Profit.
|
95 |
+
|
96 |
+
## Changelog
|
97 |
+
|
98 |
+
### 1.2.0
|
99 |
+
|
100 |
+
**Enhancements**
|
101 |
+
|
102 |
+
* Add support for custom date/time formats. Props [@Scrent](https://github.com/Scrent). ([#506](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/506))
|
103 |
+
* Simplify `wysiwyg` escaping and allow it to be overridden via the `escape_cb` parameter. ([#491](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/491))
|
104 |
+
* Add a 'Select/Deselect all' button for the `multicheck` field type.
|
105 |
+
* Add title option for [repeatable groups](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#group). Title field takes an optional replacement hash, "{#}" that will be replaced by the row number.
|
106 |
+
* New field parameter, `show_on_cb`, allows you to conditionally display a field via a callback. ([#47](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/47))
|
107 |
+
* Unit testing (the beginning). Props [@brichards](https://github.com/brichards) and [@camdensegal](https://github.com/camdensegal).
|
108 |
+
|
109 |
+
**Bug Fixes**
|
110 |
+
|
111 |
+
* Fixed issue where remove file button wouldn't clear the url field. ([#514](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/514))
|
112 |
+
* `wysiwyg` fields now allow underscores. Fixes some wysiwyg display issues in WordPress 3.8. Props [@lswilson](https://github.com/lswilson). ([#491](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/491))
|
113 |
+
* Nonce field should only be added once per page. ([#521](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/521))
|
114 |
+
* Fix `in_array` issue when a post does not have any saved terms for a taxonomy multicheck. ([#527](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/527))
|
115 |
+
* Fixed error: 'Uninitialized string offset: 0 in cmb_Meta_Box_field.php...`. Props [@DevinWalker](https://github.com/DevinWalker). ([#539](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/539), [#549](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/549)))
|
116 |
+
* Fix missing `file` field description. ([#543](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/543), [#547](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/547))
|
117 |
+
|
118 |
+
|
119 |
+
|
120 |
+
### 1.1.3
|
121 |
+
**Bug Fixes**
|
122 |
+
|
123 |
+
* Update `cmb_get_field_value` function as it was passing the parameters to `cmb_get_field` in the wrong order.
|
124 |
+
* Fix repeating fields not working correctly if meta key or prefix contained an integer. ([#503](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/503))
|
125 |
+
|
126 |
+
### 1.1.2
|
127 |
+
|
128 |
+
**Bug Fixes**
|
129 |
+
|
130 |
+
* Fix issue with `cmb_Meta_Box_types.php` calling a missing method, `image_id_from_url`. ([#502](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/502))
|
131 |
+
|
132 |
+
|
133 |
+
### 1.1.1
|
134 |
+
|
135 |
+
**Bug Fixes**
|
136 |
+
|
137 |
+
* Radio button values were not showing saved value. ([#500](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/500))
|
138 |
+
|
139 |
+
### 1.1.0
|
140 |
+
|
141 |
+
**Enhancements**
|
142 |
+
|
143 |
+
* [Repeatable groups](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#group)
|
144 |
+
* Support for more fields to be repeatable, including oEmbed field, and date, time, and color picker fields, etc.
|
145 |
+
* Codebase has been revamped to be more modular and object-oriented.
|
146 |
+
* New filter, `"cmb_{$element}_attributes" ` for modifying an element's attributes.
|
147 |
+
* Every field now supports an `attributes` parameter that takes an array of attributes. [Read more](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Field-Types#attributes).
|
148 |
+
* Removed `cmb_std_filter` in favor of `cmb_default_filter`. **THIS IS A BREAKING CHANGE**
|
149 |
+
* Better handling of labels in sidebar. They are now placed on top of the input rather than adjacent.
|
150 |
+
* Added i18n compatibility to text_money. props [@ArchCarrier](https://github.com/ArchCarrier), ([#485](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/485))
|
151 |
+
* New helper functions: `cmb_get_field` and `cmb_get_field_value` for getting access to CMB's field object and/or value.
|
152 |
+
* New JavaScript events, `cmb_add_row` and `cmb_remove_row` for hooking in and manipulating the new row's data.
|
153 |
+
* New filter, `cmb_localized_data`, for modifiying localized data passed to the CMB JS.
|
154 |
+
|
155 |
+
**Bug Fixes**
|
156 |
+
* Resolved occasional issue where only the first character of the label/value was diplayed. props [@mustardBees](https://github.com/mustardBees), ([#486](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/486))
|
157 |
+
|
158 |
+
|
159 |
+
### 1.0.2
|
160 |
+
|
161 |
+
**Enhancements**
|
162 |
+
|
163 |
+
* Change the way the `'cmb_validate_{$field['type']}'` filter works.
|
164 |
+
It is now passed a null value vs saved value. If null is returned, default sanitization will follow. **THIS IS A BREAKING CHANGE**. If you're already using this filter, take note.
|
165 |
+
* All field types that take an option array have been simplified to take `key => value` pairs (vs `array( 'name' => 'value', 'value' => 'key', )`). This effects the 'select', 'radio', 'radio_inline' field types. The 'multicheck' field type was already using the `key => value` format. Backwards compatibility has been maintained for those using the older style.
|
166 |
+
* Added default value option for `taxonomy_select` field type. props [@darlantc](https://github.com/darlantc), ([#473](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/473))
|
167 |
+
* Added `preview_size` parameter for `file_list` field type. props [@IgorCode](https://github.com/IgorCode), ([#471](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/471))
|
168 |
+
* Updated `file_list` images to be displayed horizontally instead of vertically. props [@IgorCode](https://github.com/IgorCode), ([#467](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/467))
|
169 |
+
* Use `get_the_terms` where possible since the data is cached.
|
170 |
+
|
171 |
+
**Bug Fixes**
|
172 |
+
|
173 |
+
* Fixed wysiwyg escaping slashes. props [@gregrickaby](https://github.com/gregrickaby), ([#465](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/465))
|
174 |
+
* Replaced `__DIR__`, as `dirname( __FILE__ )` is easier to maintain back-compatibility.
|
175 |
+
* Fixed missing table styling on new posts. props [@mustardBees](https://github.com/mustardBees), ([#438](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/438))
|
176 |
+
* Fix undeclared JS variable. [@veelen](https://github.com/veelen), ([#451](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/451))
|
177 |
+
* Fix `file_list` errors when removing all files and saving.
|
178 |
+
* Set correct `object_id` to be used later in `cmb_show_on` filter. [@lauravaq](https://github.com/lauravaq), ([#445](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/445))
|
179 |
+
* Fix sanitization recursion memeory issues.
|
180 |
+
|
181 |
+
### 1.0.1
|
182 |
+
|
183 |
+
**Enhancements**
|
184 |
+
|
185 |
+
* Now works with option pages and site settings. ([view example in wiki](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/wiki/Using-CMB-to-create-an-Admin-Theme-Options-Page))
|
186 |
+
* two filters to override the setting and getting of options, `cmb_override_option_get_$option_key` and `cmb_override_option_save_$option_key` respectively. Handy for using plugins like [WP Large Options](https://github.com/voceconnect/wp-large-options/) ([also here](http://vip.wordpress.com/plugins/wp-large-options/)).
|
187 |
+
* Improved styling on taxonomy (\*tease\*) and options pages and for new 3.8 admin UI.
|
188 |
+
* New sanitization class to sanitize data when saved.
|
189 |
+
* New callback field parameter, `sanitization_cb`, for performing your own sanitization.
|
190 |
+
* new `cmb_Meta_Box_types::esc()` method that handles escaping data for display.
|
191 |
+
* New callback field parameter, `escape_cb`, for performing your own data escaping, as well as a new filter, `'cmb_types_esc_'. $field['type']`.
|
192 |
+
|
193 |
+
**Bug Fixes**
|
194 |
+
|
195 |
+
* Fixed wysiwyg editor button padding. props [@corvannoorloos](https://github.com/corvannoorloos), ([#391](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/pull/391))
|
196 |
+
* A few php < 5.3 errors were addressed.
|
197 |
+
* Fields with quotation marks no longer break the input/textarea fields.
|
198 |
+
* metaboxes for Attachment pages now save correctly. Thanks [@nciske](https://github.com/nciske) for reporting. ([#412](https://github.com/WebDevStudios/Custom-Metaboxes-and-Fields-for-WordPress/issues/412))
|
199 |
+
* Occasionally fields wouldn't save because of the admin show_on filter.
|
200 |
+
* Smaller images loaded to the file field type will no longer be blown up larger than their dimensions.
|
201 |
+
|
202 |
+
### 1.0.0
|
203 |
+
* Added `text_datetime_timestamp_timezone` type, a datetime combo field with an additional timezone drop down, props [@dessibelle](https://github.com/dessibelle)
|
204 |
+
* Added `select_timezone` type, a standalone time zone select dropdown. The time zone select can be used with standalone `text_datetime_timestamp` if desired. Props [@dessibelle](https://github.com/dessibelle)
|
205 |
+
* Added `text_url` type, a basic url field. Props [@dessibelle](https://github.com/dessibelle)
|
206 |
+
* Added `text_email` type, a basic email field. Props [@dessibelle](https://github.com/dessibelle)
|
207 |
+
* Added ability to display metabox fields in frontend. Default is true, but can be overriden using the `cmb_allow_frontend filter`. If set to true, an entire metabox form can be output with the `cmb_metabox_form( $meta_box, $object_id, $echo )` function. Props [@dessibelle](https://github.com/dessibelle), [@messenlehner](https://github.com/messenlehner) & [@jtsternberg](https://github.com/jtsternberg).
|
208 |
+
* Added hook `cmb_after_table` after all metabox output. Props [@wpsmith](https://github.com/wpsmith)
|
209 |
+
* `file_list` now works like a repeatable field. Add as many files as you want. Props [@coreymcollins](https://github.com/coreymcollins)
|
210 |
+
* `text`, `text_small`, `text_medium`, `text_url`, `text_email`, & `text_money` fields now all have the option to be repeatable. Props [@jtsternberg](https://github.com/jtsternberg)
|
211 |
+
* Custom metaboxes can now be added for user meta. Add them on the user add/edit screen, or in a custom user profile edit page on the front-end. Props [@tw2113](https://github.com/tw2113), [@jtsternberg](https://github.com/jtsternberg)
|
212 |
+
|
213 |
+
### 0.9.4
|
214 |
+
* Added field "before" and "after" options for each field. Solves issue with '$' not being the desired text_money monetary symbol, props [@GaryJones](https://github.com/GaryJones)
|
215 |
+
* Added filter for 'std' default fallback value, props [@messenlehner](https://github.com/messenlehner)
|
216 |
+
* Ensure oEmbed videos fit in their respective metaboxes, props [@jtsternberg](https://github.com/jtsternberg)
|
217 |
+
* Fixed issue where an upload field with 'show_names' disabled wouldn't have the correct button label, props [@jtsternberg](https://github.com/jtsternberg)
|
218 |
+
* Better file-extension check for images, props [@GhostToast](https://github.com/GhostToast)
|
219 |
+
* New filter, `cmb_valid_img_types`, for whitelisted image file-extensions, props [@jtsternberg](https://github.com/jtsternberg)
|
220 |
+
|
221 |
+
### 0.9.3
|
222 |
+
* Added field type and field id classes to each cmb table row, props [@jtsternberg](https://github.com/jtsternberg)
|
223 |
+
|
224 |
+
### 0.9.2
|
225 |
+
* Added post type comparison to prevent storing null values for taxonomy selectors, props [@norcross](https://github.com/norcross)
|
226 |
+
|
227 |
+
### 0.9.1
|
228 |
+
* Added `oEmbed` field type with ajax display, props [@jtsternberg](https://github.com/jtsternberg)
|
229 |
+
|
230 |
+
### 0.9
|
231 |
+
* __Note: This release requires WordPress 3.3+__
|
232 |
+
* Cleaned up scripts being queued, props [@jaredatch](https://github.com/jaredatch)
|
233 |
+
* Cleaned up and reorganized jQuery, props [@GaryJones](https://github.com/GaryJones)
|
234 |
+
* Use $pagenow instead of custom $current_page, props [@jaredatch](https://github.com/jaredatch)
|
235 |
+
* Fixed CSS, removed inline styles, now all in style.css, props [@jaredatch](https://github.com/jaredatch)
|
236 |
+
* Fixed multicheck issues (issue #48), props [@jaredatch](https://github.com/jaredatch)
|
237 |
+
* Fixed jQuery UI datepicker CSS conflicting with WordPress UI elements, props [@jaredatch](https://github.com/jaredatch)
|
238 |
+
* Fixed zeros not saving in fields, props [@GaryJones](https://github.com/GaryJones)
|
239 |
+
* Fixed improper labels on radio and multicheck fields, props [@jaredatch](https://github.com/jaredatch)
|
240 |
+
* Fixed fields not rendering properly when in sidebar, props [@jaredatch](https://github.com/jaredatch)
|
241 |
+
* Fixed bug where datepicker triggers extra space after footer in Firefox (issue #14), props [@jaredatch](https://github.com/jaredatch)
|
242 |
+
* Added jQuery UI datepicker packaged with 3.3 core, props [@jaredatch](https://github.com/jaredatch)
|
243 |
+
* Added date time combo picker, props [@jaredatch](https://github.com/jaredatch)
|
244 |
+
* Added color picker, props [@jaredatch](https://github.com/jaredatch)
|
245 |
+
* Added readme.md markdown file, props [@jaredatch](https://github.com/jaredatch)
|
246 |
+
|
247 |
+
### 0.8
|
248 |
+
* Added jQuery timepicker, props [@norcross](https://github.com/norcross)
|
249 |
+
* Added 'raw' textarea to convert special HTML entities back to characters, props [@norcross](https://github.com/norcross)
|
250 |
+
* Added missing examples on example-functions.php, props [@norcross](https://github.com/norcross)
|
251 |
+
|
252 |
+
### 0.7
|
253 |
+
* Added the new wp_editor() function for the WYSIWYG dialog box, props [@jcpry](https://github.com/jcpry)
|
254 |
+
* Created 'cmb_show_on' filter to define your own Show On Filters, props [@billerickson](https://github.com/billerickson)
|
255 |
+
* Added page template show_on filter, props [@billerickson](https://github.com/billerickson)
|
256 |
+
* Improvements to the 'file' field type, props [@randyhoyt](https://github.com/randyhoyt)
|
257 |
+
* Allow for default values on 'radio' and 'radio_inline' field types, props [@billerickson](https://github.com/billerickson)
|
258 |
+
|
259 |
+
### 0.6.1
|
260 |
+
* Enabled the ability to define your own custom field types (issue #28). props [@randyhoyt](https://github.com/randyhoyt)
|
261 |
+
|
262 |
+
### 0.6
|
263 |
+
* Added the ability to limit metaboxes to certain posts by id. props [@billerickson](https://github.com/billerickson)
|
264 |
+
|
265 |
+
### 0.5
|
266 |
+
* Fixed define to prevent notices. props [@destos](https://github.com/destos)
|
267 |
+
* Added text_date_timestap option. props [@andrewyno](https://github.com/andrewyno)
|
268 |
+
* Fixed WYSIWYG paragraph breaking/spacing bug. props [@wpsmith](https://github.com/wpsmith)
|
269 |
+
* Added taxonomy_radio and taxonomies_select options. props [@c3mdigital](https://github.com/c3mdigital)
|
270 |
+
* Fixed script causing the dashboard widgets to not be collapsible.
|
271 |
+
* Fixed various spacing and whitespace inconsistencies
|
272 |
+
|
273 |
+
### 0.4
|
274 |
+
* Think we have a release that is mostly working. We'll say the initial release :)
|
275 |
+
|
276 |
+
## Known Issues
|
277 |
+
|
278 |
+
* Problem inserting file url inside field for image with caption (issue #50) May be fixed, needs testing.
|
279 |
+
* `CMB_META_BOX_URL` does not define properly in WAMP/XAMP (Windows) (issue #31) May be fixed, needs testing.
|
280 |
+
* Metabox containing WYSIWYG editor cannot be moved (this is a TinyMCE issue)
|
281 |
+
|
282 |
+
## To-do
|
283 |
+
**Enhancements**
|
284 |
+
|
285 |
+
* Fix known issues (above)
|
286 |
+
* move timepicker and datepicker jQuery inline
|
287 |
+
* support for multiple configurable timepickers/datepickers
|
288 |
+
* add ability to save fields in a single custom field
|
289 |
+
* add ability to mark fields as required
|
290 |
+
* repeatable fields (halfway there)
|
291 |
+
* look at possiblity of tabs
|
292 |
+
* look at preserving taxonomy hierarchies
|
293 |
+
* Add input attributes filter
|
294 |
+
* Always load newest version of CMB
|
295 |
+
* Helper function to easily get oembed from stored oEmbed field
|
296 |
+
|
lib/cmb_metaboxes/style.css
CHANGED
@@ -1,621 +1,621 @@
|
|
1 |
-
/**
|
2 |
-
* CMB Styling
|
3 |
-
*/
|
4 |
-
|
5 |
-
table.cmb_metabox {
|
6 |
-
clear: both;
|
7 |
-
}
|
8 |
-
|
9 |
-
table.cmb_metabox > tr:first-of-type > td,
|
10 |
-
table.cmb_metabox > tr:first-of-type > th,
|
11 |
-
table.cmb_metabox tbody > tr:first-of-type > td,
|
12 |
-
table.cmb_metabox tbody > tr:first-of-type > th,
|
13 |
-
.post-php table.cmb_metabox .cmb-nested-table td,
|
14 |
-
.post-new-php table.cmb_metabox .cmb-nested-table td,
|
15 |
-
.post-php table.cmb_metabox .repeatable-group th,
|
16 |
-
.post-new-php table.cmb_metabox .repeatable-group th,
|
17 |
-
.post-php table.cmb_metabox .repeatable-group:first-of-type,
|
18 |
-
.post-new-php table.cmb_metabox .repeatable-group:first-of-type {
|
19 |
-
border: 0;
|
20 |
-
}
|
21 |
-
|
22 |
-
.post-php table.cmb_metabox td,
|
23 |
-
.post-new-php table.cmb_metabox td,
|
24 |
-
.post-php table.cmb_metabox th,
|
25 |
-
.post-new-php table.cmb_metabox th,
|
26 |
-
.post-php table.cmb_metabox .repeatable-group,
|
27 |
-
.post-new-php table.cmb_metabox .repeatable-group,
|
28 |
-
.post-php table.cmb_metabox .repeatable-group,
|
29 |
-
.post-new-php table.cmb_metabox .repeatable-group {
|
30 |
-
border-top: 1px solid #E9E9E9;
|
31 |
-
}
|
32 |
-
|
33 |
-
.repeatable-group th {
|
34 |
-
padding: 5px;
|
35 |
-
}
|
36 |
-
|
37 |
-
.repeatable-group .shift-rows {
|
38 |
-
text-decoration: none;
|
39 |
-
margin-right: 5px;
|
40 |
-
font-size: 1.2em;
|
41 |
-
}
|
42 |
-
|
43 |
-
.repeatable-group .cmb_upload_button {
|
44 |
-
float: right;
|
45 |
-
}
|
46 |
-
|
47 |
-
#poststuff .repeatable-group h2 {
|
48 |
-
margin: 0;
|
49 |
-
}
|
50 |
-
|
51 |
-
.cmb-group-title h4 {
|
52 |
-
font-size: 1.2em;
|
53 |
-
font-weight: 500;
|
54 |
-
border-bottom: 1px solid #ddd;
|
55 |
-
}
|
56 |
-
|
57 |
-
.post-php table.cmb_metabox th, .post-new-php table.cmb_metabox th {
|
58 |
-
text-align: right;
|
59 |
-
font-weight:bold;
|
60 |
-
}
|
61 |
-
|
62 |
-
.post-php table.cmb_metabox table th, .post-new-php table.cmb_metabox table th {
|
63 |
-
text-align: left;
|
64 |
-
}
|
65 |
-
|
66 |
-
table.cmb_metabox th label {
|
67 |
-
margin-top:5px;
|
68 |
-
display:block
|
69 |
-
}
|
70 |
-
|
71 |
-
p.cmb_metabox_description {
|
72 |
-
color: #AAA;
|
73 |
-
font-style: italic;
|
74 |
-
margin: 2px 0 !important
|
75 |
-
}
|
76 |
-
|
77 |
-
span.cmb_metabox_description {
|
78 |
-
color: #AAA;
|
79 |
-
font-style: italic
|
80 |
-
}
|
81 |
-
|
82 |
-
table.cmb_metabox input, table.cmb_metabox textarea {
|
83 |
-
font-size:14px;
|
84 |
-
padding: 5px;
|
85 |
-
}
|
86 |
-
|
87 |
-
table.cmb_metabox input[type=text], table.cmb_metabox textarea {
|
88 |
-
width: 97%;
|
89 |
-
}
|
90 |
-
|
91 |
-
table.cmb_metabox textarea.cmb_textarea_code {
|
92 |
-
font-family: Consolas,Monaco,monospace;
|
93 |
-
line-height: 16px;
|
94 |
-
}
|
95 |
-
|
96 |
-
table.cmb_metabox input.cmb_text_small {
|
97 |
-
width: 100px;
|
98 |
-
margin-right: 15px
|
99 |
-
}
|
100 |
-
|
101 |
-
table.cmb_metabox input.cmb_timepicker {
|
102 |
-
width: 100px;
|
103 |
-
margin-right: 15px
|
104 |
-
}
|
105 |
-
|
106 |
-
table.cmb_metabox input.cmb_text_money {
|
107 |
-
width: 90px;
|
108 |
-
margin-right: 15px
|
109 |
-
}
|
110 |
-
|
111 |
-
table.cmb_metabox input.cmb_text_medium {
|
112 |
-
width: 230px;
|
113 |
-
margin-right: 15px
|
114 |
-
}
|
115 |
-
|
116 |
-
table.cmb_metabox input.cmb_upload_file {
|
117 |
-
width: 65%;
|
118 |
-
}
|
119 |
-
|
120 |
-
table.cmb_metabox input.ed_button{
|
121 |
-
padding:2px 4px
|
122 |
-
}
|
123 |
-
|
124 |
-
table.cmb_metabox li {
|
125 |
-
font-size:14px;
|
126 |
-
margin: 1px 0 5px 0;
|
127 |
-
line-height: 16px;
|
128 |
-
}
|
129 |
-
|
130 |
-
table.cmb_metabox ul {
|
131 |
-
padding-top:5px;
|
132 |
-
margin: 0;
|
133 |
-
}
|
134 |
-
|
135 |
-
table.cmb_metabox select {
|
136 |
-
font-size:14px;
|
137 |
-
margin-top: 3px
|
138 |
-
}
|
139 |
-
|
140 |
-
table.cmb_metabox input:focus, table.cmb_metabox textarea:focus {
|
141 |
-
background: #fffff8
|
142 |
-
}
|
143 |
-
|
144 |
-
.cmb_metabox_title {
|
145 |
-
margin: 0 0 5px 0;
|
146 |
-
padding: 5px 0 0 0;
|
147 |
-
}
|
148 |
-
|
149 |
-
.edit-tags-php .cmb_metabox_title, .profile-php .cmb_metabox_title, .user-edit-php .cmb_metabox_title {
|
150 |
-
margin-left: -10px;
|
151 |
-
}
|
152 |
-
|
153 |
-
.cmb-inline ul {
|
154 |
-
padding: 4px 0 0 0
|
155 |
-
}
|
156 |
-
|
157 |
-
.cmb-inline li {display: inline-block;
|
158 |
-
padding-right: 18px
|
159 |
-
}
|
160 |
-
|
161 |
-
table.cmb_metabox input[type="radio"] {
|
162 |
-
margin: 0 5px 0 0;
|
163 |
-
padding: 0
|
164 |
-
}
|
165 |
-
|
166 |
-
table.cmb_metabox input[type="checkbox"] {
|
167 |
-
margin: 0 5px 0 0;
|
168 |
-
padding: 0
|
169 |
-
}
|
170 |
-
|
171 |
-
table.cmb_metabox .mceLayout {
|
172 |
-
border:1px solid #DFDFDF !important
|
173 |
-
}
|
174 |
-
|
175 |
-
table.cmb_metabox .mceIframeContainer {
|
176 |
-
background:#FFF
|
177 |
-
}
|
178 |
-
|
179 |
-
table.cmb_metabox .meta_mce {
|
180 |
-
width:97%
|
181 |
-
}
|
182 |
-
|
183 |
-
table.cmb_metabox .meta_mce textarea {
|
184 |
-
width:100%
|
185 |
-
}
|
186 |
-
|
187 |
-
table.cmb_metabox .cmb_media_status {
|
188 |
-
margin: 10px 0 0 0
|
189 |
-
}
|
190 |
-
|
191 |
-
table.cmb_metabox .cmb_media_status .img_status {
|
192 |
-
clear: none;
|
193 |
-
float: left;
|
194 |
-
display: inline-block;
|
195 |
-
margin-right: 10px;
|
196 |
-
width: auto;
|
197 |
-
}
|
198 |
-
|
199 |
-
table.cmb_metabox .cmb-type-file_list .cmb_media_status .img_status {
|
200 |
-
clear: none;
|
201 |
-
float: left;
|
202 |
-
margin-right: 10px;
|
203 |
-
width: auto;
|
204 |
-
}
|
205 |
-
|
206 |
-
table.cmb_metabox .cmb_media_status .img_status, table.cmb_metabox .cmb_media_status .embed_status {
|
207 |
-
position: relative;
|
208 |
-
}
|
209 |
-
|
210 |
-
table.cmb_metabox .cmb_media_status .img_status img, table.cmb_metabox .cmb_media_status .embed_status {
|
211 |
-
border:1px solid #DFDFDF;
|
212 |
-
background: #FAFAFA;
|
213 |
-
max-width:350px;
|
214 |
-
padding: 5px;
|
215 |
-
-moz-border-radius: 2px;
|
216 |
-
border-radius: 2px
|
217 |
-
}
|
218 |
-
|
219 |
-
table.cmb_metabox .cmb_media_status .embed_status {
|
220 |
-
float: left;
|
221 |
-
max-width:800px
|
222 |
-
}
|
223 |
-
|
224 |
-
table.cmb_metabox .cmb_media_status .img_status .cmb_remove_file_button, table.cmb_metabox .cmb_media_status .embed_status .cmb_remove_file_button {
|
225 |
-
text-indent: -9999px;
|
226 |
-
background: url(images/ico-delete.png);
|
227 |
-
width: 16px;
|
228 |
-
height: 16px;
|
229 |
-
position: absolute;
|
230 |
-
top: -5px;
|
231 |
-
left: -5px
|
232 |
-
}
|
233 |
-
|
234 |
-
table.cmb_metabox .attach_list li {
|
235 |
-
clear: both;
|
236 |
-
display: inline-block;
|
237 |
-
margin-bottom: 25px;
|
238 |
-
width: 100%;
|
239 |
-
}
|
240 |
-
|
241 |
-
table.cmb_metabox .attach_list li img {
|
242 |
-
float: left;
|
243 |
-
margin-right: 10px;
|
244 |
-
}
|
245 |
-
|
246 |
-
/**
|
247 |
-
* Sidebar placement adjustments
|
248 |
-
*/
|
249 |
-
.inner-sidebar table.cmb_metabox input[type=text],
|
250 |
-
#side-sortables table.cmb_metabox input[type=text],
|
251 |
-
table.cmb_metabox textarea {
|
252 |
-
width: 95%;
|
253 |
-
}
|
254 |
-
|
255 |
-
.inner-sidebar table.cmb_metabox .cmb_media_status .img_status img,
|
256 |
-
#side-sortables table.cmb_metabox .cmb_media_status .img_status img,
|
257 |
-
.inner-sidebar table.cmb_metabox .cmb_media_status .embed_status img,
|
258 |
-
#side-sortables table.cmb_metabox .cmb_media_status .embed_status img {
|
259 |
-
width: 90%;
|
260 |
-
}
|
261 |
-
|
262 |
-
.inner-sidebar table.cmb_metabox label,
|
263 |
-
#side-sortables table.cmb_metabox label {
|
264 |
-
display: block;
|
265 |
-
font-weight: bold;
|
266 |
-
padding: 0 0 5px;
|
267 |
-
}
|
268 |
-
|
269 |
-
.inner-sidebar table.cmb_metabox .cmb_list label,
|
270 |
-
#side-sortables table.cmb_metabox .cmb_list label {
|
271 |
-
display: inline;
|
272 |
-
font-weight: normal;
|
273 |
-
}
|
274 |
-
|
275 |
-
.inner-sidebar table.cmb_metabox .cmb_metabox_description,
|
276 |
-
#side-sortables table.cmb_metabox .cmb_metabox_description {
|
277 |
-
display: block;
|
278 |
-
padding: 7px 0 0;
|
279 |
-
}
|
280 |
-
|
281 |
-
.inner-sidebar table.cmb_metabox .cmb_metabox_title,
|
282 |
-
#side-sortables table.cmb_metabox .cmb_metabox_title {
|
283 |
-
font-size: 1.2em;
|
284 |
-
font-style: italic;
|
285 |
-
}
|
286 |
-
|
287 |
-
.postbox table.cmb_metabox .cmb-spinner {
|
288 |
-
float: left;
|
289 |
-
}
|
290 |
-
|
291 |
-
/**
|
292 |
-
* Color picker
|
293 |
-
*/
|
294 |
-
table.cmb_metabox .wp-color-result, table.cmb_metabox .wp-picker-input-wrap {
|
295 |
-
vertical-align: middle;
|
296 |
-
}
|
297 |
-
|
298 |
-
table.cmb_metabox .wp-color-result, table.cmb_metabox .wp-picker-container {
|
299 |
-
margin: 0 10px 0 0;
|
300 |
-
}
|
301 |
-
|
302 |
-
|
303 |
-
/**
|
304 |
-
* Timepicker
|
305 |
-
*/
|
306 |
-
div.time-picker {
|
307 |
-
position: absolute;
|
308 |
-
height: 191px;
|
309 |
-
width:6em;
|
310 |
-
/* needed for IE */overflow: auto;
|
311 |
-
background: #fff;
|
312 |
-
border: 1px solid #aaa;
|
313 |
-
z-index: 99;
|
314 |
-
margin: 0
|
315 |
-
}
|
316 |
-
|
317 |
-
div.time-picker-12hours {
|
318 |
-
width:8em; /* needed for IE */
|
319 |
-
}
|
320 |
-
|
321 |
-
div.time-picker ul {
|
322 |
-
list-style-type: none;
|
323 |
-
margin: 0;
|
324 |
-
padding: 0;
|
325 |
-
}
|
326 |
-
|
327 |
-
div.time-picker li {
|
328 |
-
cursor: pointer;
|
329 |
-
height: 10px;
|
330 |
-
font: 14px/1 Helvetica, Arial, sans-serif;
|
331 |
-
padding: 4px 3px;
|
332 |
-
}
|
333 |
-
|
334 |
-
div.time-picker li.selected {
|
335 |
-
background: #0063CE;
|
336 |
-
color: #fff;
|
337 |
-
}
|
338 |
-
|
339 |
-
/**
|
340 |
-
* jQuery UI CSS Framework 1.8.16
|
341 |
-
*
|
342 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
343 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
344 |
-
* http://jquery.org/license
|
345 |
-
*
|
346 |
-
* http://docs.jquery.com/UI/Theming/API
|
347 |
-
*/
|
348 |
-
.cmb_element .ui-helper-hidden { display: none; }
|
349 |
-
.cmb_element .ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
|
350 |
-
.cmb_element .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
|
351 |
-
.cmb_element .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
|
352 |
-
.cmb_element .ui-helper-clearfix { display: inline-block; }
|
353 |
-
* html .ui-helper-clearfix { height:1%; }
|
354 |
-
.cmb_element .ui-helper-clearfix { display:block; }
|
355 |
-
.cmb_element .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
|
356 |
-
.cmb_element .ui-state-disabled { cursor: default !important; }
|
357 |
-
.cmb_element .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
|
358 |
-
.cmb_element .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
|
359 |
-
.cmb_element .ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
|
360 |
-
.cmb_element .ui-widget .ui-widget { font-size: 1em; }
|
361 |
-
.cmb_element .ui-widget input, .cmb_element .ui-widget select, .cmb_element .ui-widget textarea, .cmb_element .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
|
362 |
-
.cmb_element .ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
|
363 |
-
.cmb_element .ui-widget-content a { color: #222222; }
|
364 |
-
.cmb_element .ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }
|
365 |
-
.cmb_element .ui-widget-header a { color: #222222; }
|
366 |
-
.cmb_element .ui-state-default, .cmb_element .ui-widget-content .ui-state-default, .cmb_element .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; }
|
367 |
-
.cmb_element .ui-state-default a, .cmb_element .ui-state-default a:link, .cmb_element .ui-state-default a:visited { color: #555555; text-decoration: none; }
|
368 |
-
.cmb_element .ui-state-hover, .cmb_element .ui-widget-content .ui-state-hover, .cmb_element .ui-widget-header .ui-state-hover, .cmb_element .ui-state-focus, .cmb_element .ui-widget-content .ui-state-focus, .cmb_element .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
|
369 |
-
.cmb_element .ui-state-hover a, .cmb_element .ui-state-hover a:hover { color: #212121; text-decoration: none; }
|
370 |
-
.cmb_element .ui-state-active, .cmb_element .ui-widget-content .ui-state-active, .cmb_element .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
|
371 |
-
.cmb_element .ui-state-active a, .cmb_element .ui-state-active a:link, .cmb_element .ui-state-active a:visited { color: #212121; text-decoration: none; }
|
372 |
-
.cmb_element .ui-widget :active { outline: none; }
|
373 |
-
.cmb_element .ui-state-highlight, .cmb_element .ui-widget-content .ui-state-highlight, .cmb_element .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }
|
374 |
-
.cmb_element .ui-state-highlight a, .cmb_element .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
|
375 |
-
.cmb_element .ui-state-error, .cmb_element .ui-widget-content .ui-state-error, .cmb_element .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
|
376 |
-
.cmb_element .ui-state-error a, .cmb_element .ui-widget-content .ui-state-error a, .cmb_element .ui-widget-header .ui-state-error a { color: #cd0a0a; }
|
377 |
-
.cmb_element .ui-state-error-text, .cmb_element .ui-widget-content .ui-state-error-text, .cmb_element .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
|
378 |
-
.cmb_element .ui-priority-primary, .cmb_element .ui-widget-content .ui-priority-primary, .cmb_element .ui-widget-header .ui-priority-primary { font-weight: bold; }
|
379 |
-
.cmb_element .ui-priority-secondary, .cmb_element .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
|
380 |
-
.cmb_element .ui-state-disabled, .cmb_element .ui-widget-content .ui-state-disabled, .cmb_element .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
|
381 |
-
.cmb_element .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
|
382 |
-
.cmb_element .ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
|
383 |
-
.cmb_element .ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
|
384 |
-
.cmb_element .ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); }
|
385 |
-
.cmb_element .ui-state-hover .ui-icon, .cmb_element .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
|
386 |
-
.cmb_element .ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
|
387 |
-
.cmb_element .ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
|
388 |
-
.cmb_element .ui-state-error .ui-icon, .cmb_element .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
|
389 |
-
.cmb_element .ui-icon-carat-1-n { background-position: 0 0; }
|
390 |
-
.cmb_element .ui-icon-carat-1-ne { background-position: -16px 0; }
|
391 |
-
.cmb_element .ui-icon-carat-1-e { background-position: -32px 0; }
|
392 |
-
.cmb_element .ui-icon-carat-1-se { background-position: -48px 0; }
|
393 |
-
.cmb_element .ui-icon-carat-1-s { background-position: -64px 0; }
|
394 |
-
.cmb_element .ui-icon-carat-1-sw { background-position: -80px 0; }
|
395 |
-
.cmb_element .ui-icon-carat-1-w { background-position: -96px 0; }
|
396 |
-
.cmb_element .ui-icon-carat-1-nw { background-position: -112px 0; }
|
397 |
-
.cmb_element .ui-icon-carat-2-n-s { background-position: -128px 0; }
|
398 |
-
.cmb_element .ui-icon-carat-2-e-w { background-position: -144px 0; }
|
399 |
-
.cmb_element .ui-icon-triangle-1-n { background-position: 0 -16px; }
|
400 |
-
.cmb_element .ui-icon-triangle-1-ne { background-position: -16px -16px; }
|
401 |
-
.cmb_element .ui-icon-triangle-1-e { background-position: -32px -16px; }
|
402 |
-
.cmb_element .ui-icon-triangle-1-se { background-position: -48px -16px; }
|
403 |
-
.cmb_element .ui-icon-triangle-1-s { background-position: -64px -16px; }
|
404 |
-
.cmb_element .ui-icon-triangle-1-sw { background-position: -80px -16px; }
|
405 |
-
.cmb_element .ui-icon-triangle-1-w { background-position: -96px -16px; }
|
406 |
-
.cmb_element .ui-icon-triangle-1-nw { background-position: -112px -16px; }
|
407 |
-
.cmb_element .ui-icon-triangle-2-n-s { background-position: -128px -16px; }
|
408 |
-
.cmb_element .ui-icon-triangle-2-e-w { background-position: -144px -16px; }
|
409 |
-
.cmb_element .ui-icon-arrow-1-n { background-position: 0 -32px; }
|
410 |
-
.cmb_element .ui-icon-arrow-1-ne { background-position: -16px -32px; }
|
411 |
-
.cmb_element .ui-icon-arrow-1-e { background-position: -32px -32px; }
|
412 |
-
.cmb_element .ui-icon-arrow-1-se { background-position: -48px -32px; }
|
413 |
-
.cmb_element .ui-icon-arrow-1-s { background-position: -64px -32px; }
|
414 |
-
.cmb_element .ui-icon-arrow-1-sw { background-position: -80px -32px; }
|
415 |
-
.cmb_element .ui-icon-arrow-1-w { background-position: -96px -32px; }
|
416 |
-
.cmb_element .ui-icon-arrow-1-nw { background-position: -112px -32px; }
|
417 |
-
.cmb_element .ui-icon-arrow-2-n-s { background-position: -128px -32px; }
|
418 |
-
.cmb_element .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
|
419 |
-
.cmb_element .ui-icon-arrow-2-e-w { background-position: -160px -32px; }
|
420 |
-
.cmb_element .ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
|
421 |
-
.cmb_element .ui-icon-arrowstop-1-n { background-position: -192px -32px; }
|
422 |
-
.cmb_element .ui-icon-arrowstop-1-e { background-position: -208px -32px; }
|
423 |
-
.cmb_element .ui-icon-arrowstop-1-s { background-position: -224px -32px; }
|
424 |
-
.cmb_element .ui-icon-arrowstop-1-w { background-position: -240px -32px; }
|
425 |
-
.cmb_element .ui-icon-arrowthick-1-n { background-position: 0 -48px; }
|
426 |
-
.cmb_element .ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
|
427 |
-
.cmb_element .ui-icon-arrowthick-1-e { background-position: -32px -48px; }
|
428 |
-
.cmb_element .ui-icon-arrowthick-1-se { background-position: -48px -48px; }
|
429 |
-
.cmb_element .ui-icon-arrowthick-1-s { background-position: -64px -48px; }
|
430 |
-
.cmb_element .ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
|
431 |
-
.cmb_element .ui-icon-arrowthick-1-w { background-position: -96px -48px; }
|
432 |
-
.cmb_element .ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
|
433 |
-
.cmb_element .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
|
434 |
-
.cmb_element .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
|
435 |
-
.cmb_element .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
|
436 |
-
.cmb_element .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
|
437 |
-
.cmb_element .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
|
438 |
-
.cmb_element .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
|
439 |
-
.cmb_element .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
|
440 |
-
.cmb_element .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
|
441 |
-
.cmb_element .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
|
442 |
-
.cmb_element .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
|
443 |
-
.cmb_element .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
|
444 |
-
.cmb_element .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
|
445 |
-
.cmb_element .ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
|
446 |
-
.cmb_element .ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
|
447 |
-
.cmb_element .ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
|
448 |
-
.cmb_element .ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
|
449 |
-
.cmb_element .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
|
450 |
-
.cmb_element .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
|
451 |
-
.cmb_element .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
|
452 |
-
.cmb_element .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
|
453 |
-
.cmb_element .ui-icon-arrow-4 { background-position: 0 -80px; }
|
454 |
-
.cmb_element .ui-icon-arrow-4-diag { background-position: -16px -80px; }
|
455 |
-
.cmb_element .ui-icon-extlink { background-position: -32px -80px; }
|
456 |
-
.cmb_element .ui-icon-newwin { background-position: -48px -80px; }
|
457 |
-
.cmb_element .ui-icon-refresh { background-position: -64px -80px; }
|
458 |
-
.cmb_element .ui-icon-shuffle { background-position: -80px -80px; }
|
459 |
-
.cmb_element .ui-icon-transfer-e-w { background-position: -96px -80px; }
|
460 |
-
.cmb_element .ui-icon-transferthick-e-w { background-position: -112px -80px; }
|
461 |
-
.cmb_element .ui-icon-folder-collapsed { background-position: 0 -96px; }
|
462 |
-
.cmb_element .ui-icon-folder-open { background-position: -16px -96px; }
|
463 |
-
.cmb_element .ui-icon-document { background-position: -32px -96px; }
|
464 |
-
.cmb_element .ui-icon-document-b { background-position: -48px -96px; }
|
465 |
-
.cmb_element .ui-icon-note { background-position: -64px -96px; }
|
466 |
-
.cmb_element .ui-icon-mail-closed { background-position: -80px -96px; }
|
467 |
-
.cmb_element .ui-icon-mail-open { background-position: -96px -96px; }
|
468 |
-
.cmb_element .ui-icon-suitcase { background-position: -112px -96px; }
|
469 |
-
.cmb_element .ui-icon-comment { background-position: -128px -96px; }
|
470 |
-
.cmb_element .ui-icon-person { background-position: -144px -96px; }
|
471 |
-
.cmb_element .ui-icon-print { background-position: -160px -96px; }
|
472 |
-
.cmb_element .ui-icon-trash { background-position: -176px -96px; }
|
473 |
-
.cmb_element .ui-icon-locked { background-position: -192px -96px; }
|
474 |
-
.cmb_element .ui-icon-unlocked { background-position: -208px -96px; }
|
475 |
-
.cmb_element .ui-icon-bookmark { background-position: -224px -96px; }
|
476 |
-
.cmb_element .ui-icon-tag { background-position: -240px -96px; }
|
477 |
-
.cmb_element .ui-icon-home { background-position: 0 -112px; }
|
478 |
-
.cmb_element .ui-icon-flag { background-position: -16px -112px; }
|
479 |
-
.cmb_element .ui-icon-calendar { background-position: -32px -112px; }
|
480 |
-
.cmb_element .ui-icon-cart { background-position: -48px -112px; }
|
481 |
-
.cmb_element .ui-icon-pencil { background-position: -64px -112px; }
|
482 |
-
.cmb_element .ui-icon-clock { background-position: -80px -112px; }
|
483 |
-
.cmb_element .ui-icon-disk { background-position: -96px -112px; }
|
484 |
-
.cmb_element .ui-icon-calculator { background-position: -112px -112px; }
|
485 |
-
.cmb_element .ui-icon-zoomin { background-position: -128px -112px; }
|
486 |
-
.cmb_element .ui-icon-zoomout { background-position: -144px -112px; }
|
487 |
-
.cmb_element .ui-icon-search { background-position: -160px -112px; }
|
488 |
-
.cmb_element .ui-icon-wrench { background-position: -176px -112px; }
|
489 |
-
.cmb_element .ui-icon-gear { background-position: -192px -112px; }
|
490 |
-
.cmb_element .ui-icon-heart { background-position: -208px -112px; }
|
491 |
-
.cmb_element .ui-icon-star { background-position: -224px -112px; }
|
492 |
-
.cmb_element .ui-icon-link { background-position: -240px -112px; }
|
493 |
-
.cmb_element .ui-icon-cancel { background-position: 0 -128px; }
|
494 |
-
.cmb_element .ui-icon-plus { background-position: -16px -128px; }
|
495 |
-
.cmb_element .ui-icon-plusthick { background-position: -32px -128px; }
|
496 |
-
.cmb_element .ui-icon-minus { background-position: -48px -128px; }
|
497 |
-
.cmb_element .ui-icon-minusthick { background-position: -64px -128px; }
|
498 |
-
.cmb_element .ui-icon-close { background-position: -80px -128px; }
|
499 |
-
.cmb_element .ui-icon-closethick { background-position: -96px -128px; }
|
500 |
-
.cmb_element .ui-icon-key { background-position: -112px -128px; }
|
501 |
-
.cmb_element .ui-icon-lightbulb { background-position: -128px -128px; }
|
502 |
-
.cmb_element .ui-icon-scissors { background-position: -144px -128px; }
|
503 |
-
.cmb_element .ui-icon-clipboard { background-position: -160px -128px; }
|
504 |
-
.cmb_element .ui-icon-copy { background-position: -176px -128px; }
|
505 |
-
.cmb_element .ui-icon-contact { background-position: -192px -128px; }
|
506 |
-
.cmb_element .ui-icon-image { background-position: -208px -128px; }
|
507 |
-
.cmb_element .ui-icon-video { background-position: -224px -128px; }
|
508 |
-
.cmb_element .ui-icon-script { background-position: -240px -128px; }
|
509 |
-
.cmb_element .ui-icon-alert { background-position: 0 -144px; }
|
510 |
-
.cmb_element .ui-icon-info { background-position: -16px -144px; }
|
511 |
-
.cmb_element .ui-icon-notice { background-position: -32px -144px; }
|
512 |
-
.cmb_element .ui-icon-help { background-position: -48px -144px; }
|
513 |
-
.cmb_element .ui-icon-check { background-position: -64px -144px; }
|
514 |
-
.cmb_element .ui-icon-bullet { background-position: -80px -144px; }
|
515 |
-
.cmb_element .ui-icon-radio-off { background-position: -96px -144px; }
|
516 |
-
.cmb_element .ui-icon-radio-on { background-position: -112px -144px; }
|
517 |
-
.cmb_element .ui-icon-pin-w { background-position: -128px -144px; }
|
518 |
-
.cmb_element .ui-icon-pin-s { background-position: -144px -144px; }
|
519 |
-
.cmb_element .ui-icon-play { background-position: 0 -160px; }
|
520 |
-
.cmb_element .ui-icon-pause { background-position: -16px -160px; }
|
521 |
-
.cmb_element .ui-icon-seek-next { background-position: -32px -160px; }
|
522 |
-
.cmb_element .ui-icon-seek-prev { background-position: -48px -160px; }
|
523 |
-
.cmb_element .ui-icon-seek-end { background-position: -64px -160px; }
|
524 |
-
.cmb_element .ui-icon-seek-start { background-position: -80px -160px; }
|
525 |
-
.cmb_element .ui-icon-seek-first { background-position: -80px -160px; }
|
526 |
-
.cmb_element .ui-icon-stop { background-position: -96px -160px; }
|
527 |
-
.cmb_element .ui-icon-eject { background-position: -112px -160px; }
|
528 |
-
.cmb_element .ui-icon-volume-off { background-position: -128px -160px; }
|
529 |
-
.cmb_element .ui-icon-volume-on { background-position: -144px -160px; }
|
530 |
-
.cmb_element .ui-icon-power { background-position: 0 -176px; }
|
531 |
-
.cmb_element .ui-icon-signal-diag { background-position: -16px -176px; }
|
532 |
-
.cmb_element .ui-icon-signal { background-position: -32px -176px; }
|
533 |
-
.cmb_element .ui-icon-battery-0 { background-position: -48px -176px; }
|
534 |
-
.cmb_element .ui-icon-battery-1 { background-position: -64px -176px; }
|
535 |
-
.cmb_element .ui-icon-battery-2 { background-position: -80px -176px; }
|
536 |
-
.cmb_element .ui-icon-battery-3 { background-position: -96px -176px; }
|
537 |
-
.cmb_element .ui-icon-circle-plus { background-position: 0 -192px; }
|
538 |
-
.cmb_element .ui-icon-circle-minus { background-position: -16px -192px; }
|
539 |
-
.cmb_element .ui-icon-circle-close { background-position: -32px -192px; }
|
540 |
-
.cmb_element .ui-icon-circle-triangle-e { background-position: -48px -192px; }
|
541 |
-
.cmb_element .ui-icon-circle-triangle-s { background-position: -64px -192px; }
|
542 |
-
.cmb_element .ui-icon-circle-triangle-w { background-position: -80px -192px; }
|
543 |
-
.cmb_element .ui-icon-circle-triangle-n { background-position: -96px -192px; }
|
544 |
-
.cmb_element .ui-icon-circle-arrow-e { background-position: -112px -192px; }
|
545 |
-
.cmb_element .ui-icon-circle-arrow-s { background-position: -128px -192px; }
|
546 |
-
.cmb_element .ui-icon-circle-arrow-w { background-position: -144px -192px; }
|
547 |
-
.cmb_element .ui-icon-circle-arrow-n { background-position: -160px -192px; }
|
548 |
-
.cmb_element .ui-icon-circle-zoomin { background-position: -176px -192px; }
|
549 |
-
.cmb_element .ui-icon-circle-zoomout { background-position: -192px -192px; }
|
550 |
-
.cmb_element .ui-icon-circle-check { background-position: -208px -192px; }
|
551 |
-
.cmb_element .ui-icon-circlesmall-plus { background-position: 0 -208px; }
|
552 |
-
.cmb_element .ui-icon-circlesmall-minus { background-position: -16px -208px; }
|
553 |
-
.cmb_element .ui-icon-circlesmall-close { background-position: -32px -208px; }
|
554 |
-
.cmb_element .ui-icon-squaresmall-plus { background-position: -48px -208px; }
|
555 |
-
.cmb_element .ui-icon-squaresmall-minus { background-position: -64px -208px; }
|
556 |
-
.cmb_element .ui-icon-squaresmall-close { background-position: -80px -208px; }
|
557 |
-
.cmb_element .ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
|
558 |
-
.cmb_element .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
|
559 |
-
.cmb_element .ui-icon-grip-solid-vertical { background-position: -32px -224px; }
|
560 |
-
.cmb_element .ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
|
561 |
-
.cmb_element .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
|
562 |
-
.cmb_element .ui-icon-grip-diagonal-se { background-position: -80px -224px; }
|
563 |
-
.cmb_element .ui-corner-all, .cmb_element .ui-corner-top, .cmb_element .ui-corner-left, .cmb_element .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
|
564 |
-
.cmb_element .ui-corner-all, .cmb_element .ui-corner-top, .cmb_element .ui-corner-right, .cmb_element .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
|
565 |
-
.cmb_element .ui-corner-all, .cmb_element .ui-corner-bottom, .cmb_element .ui-corner-left, .cmb_element .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
|
566 |
-
.cmb_element .ui-corner-all, .cmb_element .ui-corner-bottom, .cmb_element .ui-corner-right, .cmb_element .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
|
567 |
-
.cmb_element .ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
|
568 |
-
.cmb_element .ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }
|
569 |
-
.cmb_element .ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
|
570 |
-
.cmb_element .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
|
571 |
-
.cmb_element .ui-datepicker .ui-datepicker-prev, .cmb_element .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
|
572 |
-
.cmb_element .ui-datepicker .ui-datepicker-prev-hover, .cmb_element .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
|
573 |
-
.cmb_element .ui-datepicker .ui-datepicker-prev { left:2px; }
|
574 |
-
.cmb_element .ui-datepicker .ui-datepicker-next { right:2px; }
|
575 |
-
.cmb_element .ui-datepicker .ui-datepicker-prev-hover { left:1px; }
|
576 |
-
.cmb_element .ui-datepicker .ui-datepicker-next-hover { right:1px; }
|
577 |
-
.cmb_element .ui-datepicker .ui-datepicker-prev span, .cmb_element .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
|
578 |
-
.cmb_element .ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
|
579 |
-
.cmb_element .ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
|
580 |
-
.cmb_element .ui-datepicker select.ui-datepicker-month-year {width: 100%;}
|
581 |
-
.cmb_element .ui-datepicker select.ui-datepicker-month,
|
582 |
-
.cmb_element .ui-datepicker select.ui-datepicker-year { width: 49%;}
|
583 |
-
.cmb_element .ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
|
584 |
-
.cmb_element .ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
|
585 |
-
.cmb_element .ui-datepicker td { border: 0; padding: 1px; }
|
586 |
-
.cmb_element .ui-datepicker td span, .cmb_element .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
|
587 |
-
.cmb_element .ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
|
588 |
-
.cmb_element .ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
|
589 |
-
.cmb_element .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
|
590 |
-
.cmb_element .ui-datepicker.ui-datepicker-multi { width:auto; }
|
591 |
-
.cmb_element .ui-datepicker-multi .ui-datepicker-group { float:left; }
|
592 |
-
.cmb_element .ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
|
593 |
-
.cmb_element .ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
|
594 |
-
.cmb_element .ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
|
595 |
-
.cmb_element .ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
|
596 |
-
.cmb_element .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
|
597 |
-
.cmb_element .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
|
598 |
-
.cmb_element .ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
|
599 |
-
.cmb_element .ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
|
600 |
-
.cmb_element .ui-datepicker-rtl { direction: rtl; }
|
601 |
-
.cmb_element .ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
|
602 |
-
.cmb_element .ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
|
603 |
-
.cmb_element .ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
|
604 |
-
.cmb_element .ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
|
605 |
-
.cmb_element .ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
|
606 |
-
.cmb_element .ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
|
607 |
-
.cmb_element .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
|
608 |
-
.cmb_element .ui-datepicker-rtl .ui-datepicker-group { float:right; }
|
609 |
-
.cmb_element .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
|
610 |
-
.cmb_element .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
|
611 |
-
.cmb_element .ui-datepicker-cover {
|
612 |
-
display: none; /*sorry for IE5*/
|
613 |
-
display/**/: block; /*sorry for IE5*/
|
614 |
-
position: absolute; /*must have*/
|
615 |
-
z-index: -1; /*must have*/
|
616 |
-
filter: mask(); /*must have*/
|
617 |
-
top: -4px; /*must have*/
|
618 |
-
left: -4px; /*must have*/
|
619 |
-
width: 200px; /*must have*/
|
620 |
-
height: 200px; /*must have*/
|
621 |
-
}
|
1 |
+
/**
|
2 |
+
* CMB Styling
|
3 |
+
*/
|
4 |
+
|
5 |
+
table.cmb_metabox {
|
6 |
+
clear: both;
|
7 |
+
}
|
8 |
+
|
9 |
+
table.cmb_metabox > tr:first-of-type > td,
|
10 |
+
table.cmb_metabox > tr:first-of-type > th,
|
11 |
+
table.cmb_metabox tbody > tr:first-of-type > td,
|
12 |
+
table.cmb_metabox tbody > tr:first-of-type > th,
|
13 |
+
.post-php table.cmb_metabox .cmb-nested-table td,
|
14 |
+
.post-new-php table.cmb_metabox .cmb-nested-table td,
|
15 |
+
.post-php table.cmb_metabox .repeatable-group th,
|
16 |
+
.post-new-php table.cmb_metabox .repeatable-group th,
|
17 |
+
.post-php table.cmb_metabox .repeatable-group:first-of-type,
|
18 |
+
.post-new-php table.cmb_metabox .repeatable-group:first-of-type {
|
19 |
+
border: 0;
|
20 |
+
}
|
21 |
+
|
22 |
+
.post-php table.cmb_metabox td,
|
23 |
+
.post-new-php table.cmb_metabox td,
|
24 |
+
.post-php table.cmb_metabox th,
|
25 |
+
.post-new-php table.cmb_metabox th,
|
26 |
+
.post-php table.cmb_metabox .repeatable-group,
|
27 |
+
.post-new-php table.cmb_metabox .repeatable-group,
|
28 |
+
.post-php table.cmb_metabox .repeatable-group,
|
29 |
+
.post-new-php table.cmb_metabox .repeatable-group {
|
30 |
+
border-top: 1px solid #E9E9E9;
|
31 |
+
}
|
32 |
+
|
33 |
+
.repeatable-group th {
|
34 |
+
padding: 5px;
|
35 |
+
}
|
36 |
+
|
37 |
+
.repeatable-group .shift-rows {
|
38 |
+
text-decoration: none;
|
39 |
+
margin-right: 5px;
|
40 |
+
font-size: 1.2em;
|
41 |
+
}
|
42 |
+
|
43 |
+
.repeatable-group .cmb_upload_button {
|
44 |
+
float: right;
|
45 |
+
}
|
46 |
+
|
47 |
+
#poststuff .repeatable-group h2 {
|
48 |
+
margin: 0;
|
49 |
+
}
|
50 |
+
|
51 |
+
.cmb-group-title h4 {
|
52 |
+
font-size: 1.2em;
|
53 |
+
font-weight: 500;
|
54 |
+
border-bottom: 1px solid #ddd;
|
55 |
+
}
|
56 |
+
|
57 |
+
.post-php table.cmb_metabox th, .post-new-php table.cmb_metabox th {
|
58 |
+
text-align: right;
|
59 |
+
font-weight:bold;
|
60 |
+
}
|
61 |
+
|
62 |
+
.post-php table.cmb_metabox table th, .post-new-php table.cmb_metabox table th {
|
63 |
+
text-align: left;
|
64 |
+
}
|
65 |
+
|
66 |
+
table.cmb_metabox th label {
|
67 |
+
margin-top:5px;
|
68 |
+
display:block
|
69 |
+
}
|
70 |
+
|
71 |
+
p.cmb_metabox_description {
|
72 |
+
color: #AAA;
|
73 |
+
font-style: italic;
|
74 |
+
margin: 2px 0 !important
|
75 |
+
}
|
76 |
+
|
77 |
+
span.cmb_metabox_description {
|
78 |
+
color: #AAA;
|
79 |
+
font-style: italic
|
80 |
+
}
|
81 |
+
|
82 |
+
table.cmb_metabox input, table.cmb_metabox textarea {
|
83 |
+
font-size:14px;
|
84 |
+
padding: 5px;
|
85 |
+
}
|
86 |
+
|
87 |
+
table.cmb_metabox input[type=text], table.cmb_metabox textarea {
|
88 |
+
width: 97%;
|
89 |
+
}
|
90 |
+
|
91 |
+
table.cmb_metabox textarea.cmb_textarea_code {
|
92 |
+
font-family: Consolas,Monaco,monospace;
|
93 |
+
line-height: 16px;
|
94 |
+
}
|
95 |
+
|
96 |
+
table.cmb_metabox input.cmb_text_small {
|
97 |
+
width: 100px;
|
98 |
+
margin-right: 15px
|
99 |
+
}
|
100 |
+
|
101 |
+
table.cmb_metabox input.cmb_timepicker {
|
102 |
+
width: 100px;
|
103 |
+
margin-right: 15px
|
104 |
+
}
|
105 |
+
|
106 |
+
table.cmb_metabox input.cmb_text_money {
|
107 |
+
width: 90px;
|
108 |
+
margin-right: 15px
|
109 |
+
}
|
110 |
+
|
111 |
+
table.cmb_metabox input.cmb_text_medium {
|
112 |
+
width: 230px;
|
113 |
+
margin-right: 15px
|
114 |
+
}
|
115 |
+
|
116 |
+
table.cmb_metabox input.cmb_upload_file {
|
117 |
+
width: 65%;
|
118 |
+
}
|
119 |
+
|
120 |
+
table.cmb_metabox input.ed_button{
|
121 |
+
padding:2px 4px
|
122 |
+
}
|
123 |
+
|
124 |
+
table.cmb_metabox li {
|
125 |
+
font-size:14px;
|
126 |
+
margin: 1px 0 5px 0;
|
127 |
+
line-height: 16px;
|
128 |
+
}
|
129 |
+
|
130 |
+
table.cmb_metabox ul {
|
131 |
+
padding-top:5px;
|
132 |
+
margin: 0;
|
133 |
+
}
|
134 |
+
|
135 |
+
table.cmb_metabox select {
|
136 |
+
font-size:14px;
|
137 |
+
margin-top: 3px
|
138 |
+
}
|
139 |
+
|
140 |
+
table.cmb_metabox input:focus, table.cmb_metabox textarea:focus {
|
141 |
+
background: #fffff8
|
142 |
+
}
|
143 |
+
|
144 |
+
.cmb_metabox_title {
|
145 |
+
margin: 0 0 5px 0;
|
146 |
+
padding: 5px 0 0 0;
|
147 |
+
}
|
148 |
+
|
149 |
+
.edit-tags-php .cmb_metabox_title, .profile-php .cmb_metabox_title, .user-edit-php .cmb_metabox_title {
|
150 |
+
margin-left: -10px;
|
151 |
+
}
|
152 |
+
|
153 |
+
.cmb-inline ul {
|
154 |
+
padding: 4px 0 0 0
|
155 |
+
}
|
156 |
+
|
157 |
+
.cmb-inline li {display: inline-block;
|
158 |
+
padding-right: 18px
|
159 |
+
}
|
160 |
+
|
161 |
+
table.cmb_metabox input[type="radio"] {
|
162 |
+
margin: 0 5px 0 0;
|
163 |
+
padding: 0
|
164 |
+
}
|
165 |
+
|
166 |
+
table.cmb_metabox input[type="checkbox"] {
|
167 |
+
margin: 0 5px 0 0;
|
168 |
+
padding: 0
|
169 |
+
}
|
170 |
+
|
171 |
+
table.cmb_metabox .mceLayout {
|
172 |
+
border:1px solid #DFDFDF !important
|
173 |
+
}
|
174 |
+
|
175 |
+
table.cmb_metabox .mceIframeContainer {
|
176 |
+
background:#FFF
|
177 |
+
}
|
178 |
+
|
179 |
+
table.cmb_metabox .meta_mce {
|
180 |
+
width:97%
|
181 |
+
}
|
182 |
+
|
183 |
+
table.cmb_metabox .meta_mce textarea {
|
184 |
+
width:100%
|
185 |
+
}
|
186 |
+
|
187 |
+
table.cmb_metabox .cmb_media_status {
|
188 |
+
margin: 10px 0 0 0
|
189 |
+
}
|
190 |
+
|
191 |
+
table.cmb_metabox .cmb_media_status .img_status {
|
192 |
+
clear: none;
|
193 |
+
float: left;
|
194 |
+
display: inline-block;
|
195 |
+
margin-right: 10px;
|
196 |
+
width: auto;
|
197 |
+
}
|
198 |
+
|
199 |
+
table.cmb_metabox .cmb-type-file_list .cmb_media_status .img_status {
|
200 |
+
clear: none;
|
201 |
+
float: left;
|
202 |
+
margin-right: 10px;
|
203 |
+
width: auto;
|
204 |
+
}
|
205 |
+
|
206 |
+
table.cmb_metabox .cmb_media_status .img_status, table.cmb_metabox .cmb_media_status .embed_status {
|
207 |
+
position: relative;
|
208 |
+
}
|
209 |
+
|
210 |
+
table.cmb_metabox .cmb_media_status .img_status img, table.cmb_metabox .cmb_media_status .embed_status {
|
211 |
+
border:1px solid #DFDFDF;
|
212 |
+
background: #FAFAFA;
|
213 |
+
max-width:350px;
|
214 |
+
padding: 5px;
|
215 |
+
-moz-border-radius: 2px;
|
216 |
+
border-radius: 2px
|
217 |
+
}
|
218 |
+
|
219 |
+
table.cmb_metabox .cmb_media_status .embed_status {
|
220 |
+
float: left;
|
221 |
+
max-width:800px
|
222 |
+
}
|
223 |
+
|
224 |
+
table.cmb_metabox .cmb_media_status .img_status .cmb_remove_file_button, table.cmb_metabox .cmb_media_status .embed_status .cmb_remove_file_button {
|
225 |
+
text-indent: -9999px;
|
226 |
+
background: url(images/ico-delete.png);
|
227 |
+
width: 16px;
|
228 |
+
height: 16px;
|
229 |
+
position: absolute;
|
230 |
+
top: -5px;
|
231 |
+
left: -5px
|
232 |
+
}
|
233 |
+
|
234 |
+
table.cmb_metabox .attach_list li {
|
235 |
+
clear: both;
|
236 |
+
display: inline-block;
|
237 |
+
margin-bottom: 25px;
|
238 |
+
width: 100%;
|
239 |
+
}
|
240 |
+
|
241 |
+
table.cmb_metabox .attach_list li img {
|
242 |
+
float: left;
|
243 |
+
margin-right: 10px;
|
244 |
+
}
|
245 |
+
|
246 |
+
/**
|
247 |
+
* Sidebar placement adjustments
|
248 |
+
*/
|
249 |
+
.inner-sidebar table.cmb_metabox input[type=text],
|
250 |
+
#side-sortables table.cmb_metabox input[type=text],
|
251 |
+
table.cmb_metabox textarea {
|
252 |
+
width: 95%;
|
253 |
+
}
|
254 |
+
|
255 |
+
.inner-sidebar table.cmb_metabox .cmb_media_status .img_status img,
|
256 |
+
#side-sortables table.cmb_metabox .cmb_media_status .img_status img,
|
257 |
+
.inner-sidebar table.cmb_metabox .cmb_media_status .embed_status img,
|
258 |
+
#side-sortables table.cmb_metabox .cmb_media_status .embed_status img {
|
259 |
+
width: 90%;
|
260 |
+
}
|
261 |
+
|
262 |
+
.inner-sidebar table.cmb_metabox label,
|
263 |
+
#side-sortables table.cmb_metabox label {
|
264 |
+
display: block;
|
265 |
+
font-weight: bold;
|
266 |
+
padding: 0 0 5px;
|
267 |
+
}
|
268 |
+
|
269 |
+
.inner-sidebar table.cmb_metabox .cmb_list label,
|
270 |
+
#side-sortables table.cmb_metabox .cmb_list label {
|
271 |
+
display: inline;
|
272 |
+
font-weight: normal;
|
273 |
+
}
|
274 |
+
|
275 |
+
.inner-sidebar table.cmb_metabox .cmb_metabox_description,
|
276 |
+
#side-sortables table.cmb_metabox .cmb_metabox_description {
|
277 |
+
display: block;
|
278 |
+
padding: 7px 0 0;
|
279 |
+
}
|
280 |
+
|
281 |
+
.inner-sidebar table.cmb_metabox .cmb_metabox_title,
|
282 |
+
#side-sortables table.cmb_metabox .cmb_metabox_title {
|
283 |
+
font-size: 1.2em;
|
284 |
+
font-style: italic;
|
285 |
+
}
|
286 |
+
|
287 |
+
.postbox table.cmb_metabox .cmb-spinner {
|
288 |
+
float: left;
|
289 |
+
}
|
290 |
+
|
291 |
+
/**
|
292 |
+
* Color picker
|
293 |
+
*/
|
294 |
+
table.cmb_metabox .wp-color-result, table.cmb_metabox .wp-picker-input-wrap {
|
295 |
+
vertical-align: middle;
|
296 |
+
}
|
297 |
+
|
298 |
+
table.cmb_metabox .wp-color-result, table.cmb_metabox .wp-picker-container {
|
299 |
+
margin: 0 10px 0 0;
|
300 |
+
}
|
301 |
+
|
302 |
+
|
303 |
+
/**
|
304 |
+
* Timepicker
|
305 |
+
*/
|
306 |
+
div.time-picker {
|
307 |
+
position: absolute;
|
308 |
+
height: 191px;
|
309 |
+
width:6em;
|
310 |
+
/* needed for IE */overflow: auto;
|
311 |
+
background: #fff;
|
312 |
+
border: 1px solid #aaa;
|
313 |
+
z-index: 99;
|
314 |
+
margin: 0
|
315 |
+
}
|
316 |
+
|
317 |
+
div.time-picker-12hours {
|
318 |
+
width:8em; /* needed for IE */
|
319 |
+
}
|
320 |
+
|
321 |
+
div.time-picker ul {
|
322 |
+
list-style-type: none;
|
323 |
+
margin: 0;
|
324 |
+
padding: 0;
|
325 |
+
}
|
326 |
+
|
327 |
+
div.time-picker li {
|
328 |
+
cursor: pointer;
|
329 |
+
height: 10px;
|
330 |
+
font: 14px/1 Helvetica, Arial, sans-serif;
|
331 |
+
padding: 4px 3px;
|
332 |
+
}
|
333 |
+
|
334 |
+
div.time-picker li.selected {
|
335 |
+
background: #0063CE;
|
336 |
+
color: #fff;
|
337 |
+
}
|
338 |
+
|
339 |
+
/**
|
340 |
+
* jQuery UI CSS Framework 1.8.16
|
341 |
+
*
|
342 |
+
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
343 |
+
* Dual licensed under the MIT or GPL Version 2 licenses.
|
344 |
+
* http://jquery.org/license
|
345 |
+
*
|
346 |
+
* http://docs.jquery.com/UI/Theming/API
|
347 |
+
*/
|
348 |
+
.cmb_element .ui-helper-hidden { display: none; }
|
349 |
+
.cmb_element .ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
|
350 |
+
.cmb_element .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
|
351 |
+
.cmb_element .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
|
352 |
+
.cmb_element .ui-helper-clearfix { display: inline-block; }
|
353 |
+
* html .ui-helper-clearfix { height:1%; }
|
354 |
+
.cmb_element .ui-helper-clearfix { display:block; }
|
355 |
+
.cmb_element .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
|
356 |
+
.cmb_element .ui-state-disabled { cursor: default !important; }
|
357 |
+
.cmb_element .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
|
358 |
+
.cmb_element .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
|
359 |
+
.cmb_element .ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
|
360 |
+
.cmb_element .ui-widget .ui-widget { font-size: 1em; }
|
361 |
+
.cmb_element .ui-widget input, .cmb_element .ui-widget select, .cmb_element .ui-widget textarea, .cmb_element .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
|
362 |
+
.cmb_element .ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
|
363 |
+
.cmb_element .ui-widget-content a { color: #222222; }
|
364 |
+
.cmb_element .ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }
|
365 |
+
.cmb_element .ui-widget-header a { color: #222222; }
|
366 |
+
.cmb_element .ui-state-default, .cmb_element .ui-widget-content .ui-state-default, .cmb_element .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; }
|
367 |
+
.cmb_element .ui-state-default a, .cmb_element .ui-state-default a:link, .cmb_element .ui-state-default a:visited { color: #555555; text-decoration: none; }
|
368 |
+
.cmb_element .ui-state-hover, .cmb_element .ui-widget-content .ui-state-hover, .cmb_element .ui-widget-header .ui-state-hover, .cmb_element .ui-state-focus, .cmb_element .ui-widget-content .ui-state-focus, .cmb_element .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
|
369 |
+
.cmb_element .ui-state-hover a, .cmb_element .ui-state-hover a:hover { color: #212121; text-decoration: none; }
|
370 |
+
.cmb_element .ui-state-active, .cmb_element .ui-widget-content .ui-state-active, .cmb_element .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
|
371 |
+
.cmb_element .ui-state-active a, .cmb_element .ui-state-active a:link, .cmb_element .ui-state-active a:visited { color: #212121; text-decoration: none; }
|
372 |
+
.cmb_element .ui-widget :active { outline: none; }
|
373 |
+
.cmb_element .ui-state-highlight, .cmb_element .ui-widget-content .ui-state-highlight, .cmb_element .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }
|
374 |
+
.cmb_element .ui-state-highlight a, .cmb_element .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
|
375 |
+
.cmb_element .ui-state-error, .cmb_element .ui-widget-content .ui-state-error, .cmb_element .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
|
376 |
+
.cmb_element .ui-state-error a, .cmb_element .ui-widget-content .ui-state-error a, .cmb_element .ui-widget-header .ui-state-error a { color: #cd0a0a; }
|
377 |
+
.cmb_element .ui-state-error-text, .cmb_element .ui-widget-content .ui-state-error-text, .cmb_element .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
|
378 |
+
.cmb_element .ui-priority-primary, .cmb_element .ui-widget-content .ui-priority-primary, .cmb_element .ui-widget-header .ui-priority-primary { font-weight: bold; }
|
379 |
+
.cmb_element .ui-priority-secondary, .cmb_element .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
|
380 |
+
.cmb_element .ui-state-disabled, .cmb_element .ui-widget-content .ui-state-disabled, .cmb_element .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
|
381 |
+
.cmb_element .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
|
382 |
+
.cmb_element .ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
|
383 |
+
.cmb_element .ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
|
384 |
+
.cmb_element .ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); }
|
385 |
+
.cmb_element .ui-state-hover .ui-icon, .cmb_element .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
|
386 |
+
.cmb_element .ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
|
387 |
+
.cmb_element .ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
|
388 |
+
.cmb_element .ui-state-error .ui-icon, .cmb_element .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
|
389 |
+
.cmb_element .ui-icon-carat-1-n { background-position: 0 0; }
|
390 |
+
.cmb_element .ui-icon-carat-1-ne { background-position: -16px 0; }
|
391 |
+
.cmb_element .ui-icon-carat-1-e { background-position: -32px 0; }
|
392 |
+
.cmb_element .ui-icon-carat-1-se { background-position: -48px 0; }
|
393 |
+
.cmb_element .ui-icon-carat-1-s { background-position: -64px 0; }
|
394 |
+
.cmb_element .ui-icon-carat-1-sw { background-position: -80px 0; }
|
395 |
+
.cmb_element .ui-icon-carat-1-w { background-position: -96px 0; }
|
396 |
+
.cmb_element .ui-icon-carat-1-nw { background-position: -112px 0; }
|
397 |
+
.cmb_element .ui-icon-carat-2-n-s { background-position: -128px 0; }
|
398 |
+
.cmb_element .ui-icon-carat-2-e-w { background-position: -144px 0; }
|
399 |
+
.cmb_element .ui-icon-triangle-1-n { background-position: 0 -16px; }
|
400 |
+
.cmb_element .ui-icon-triangle-1-ne { background-position: -16px -16px; }
|
401 |
+
.cmb_element .ui-icon-triangle-1-e { background-position: -32px -16px; }
|
402 |
+
.cmb_element .ui-icon-triangle-1-se { background-position: -48px -16px; }
|
403 |
+
.cmb_element .ui-icon-triangle-1-s { background-position: -64px -16px; }
|
404 |
+
.cmb_element .ui-icon-triangle-1-sw { background-position: -80px -16px; }
|
405 |
+
.cmb_element .ui-icon-triangle-1-w { background-position: -96px -16px; }
|
406 |
+
.cmb_element .ui-icon-triangle-1-nw { background-position: -112px -16px; }
|
407 |
+
.cmb_element .ui-icon-triangle-2-n-s { background-position: -128px -16px; }
|
408 |
+
.cmb_element .ui-icon-triangle-2-e-w { background-position: -144px -16px; }
|
409 |
+
.cmb_element .ui-icon-arrow-1-n { background-position: 0 -32px; }
|
410 |
+
.cmb_element .ui-icon-arrow-1-ne { background-position: -16px -32px; }
|
411 |
+
.cmb_element .ui-icon-arrow-1-e { background-position: -32px -32px; }
|
412 |
+
.cmb_element .ui-icon-arrow-1-se { background-position: -48px -32px; }
|
413 |
+
.cmb_element .ui-icon-arrow-1-s { background-position: -64px -32px; }
|
414 |
+
.cmb_element .ui-icon-arrow-1-sw { background-position: -80px -32px; }
|
415 |
+
.cmb_element .ui-icon-arrow-1-w { background-position: -96px -32px; }
|
416 |
+
.cmb_element .ui-icon-arrow-1-nw { background-position: -112px -32px; }
|
417 |
+
.cmb_element .ui-icon-arrow-2-n-s { background-position: -128px -32px; }
|
418 |
+
.cmb_element .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
|
419 |
+
.cmb_element .ui-icon-arrow-2-e-w { background-position: -160px -32px; }
|
420 |
+
.cmb_element .ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
|
421 |
+
.cmb_element .ui-icon-arrowstop-1-n { background-position: -192px -32px; }
|
422 |
+
.cmb_element .ui-icon-arrowstop-1-e { background-position: -208px -32px; }
|
423 |
+
.cmb_element .ui-icon-arrowstop-1-s { background-position: -224px -32px; }
|
424 |
+
.cmb_element .ui-icon-arrowstop-1-w { background-position: -240px -32px; }
|
425 |
+
.cmb_element .ui-icon-arrowthick-1-n { background-position: 0 -48px; }
|
426 |
+
.cmb_element .ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
|
427 |
+
.cmb_element .ui-icon-arrowthick-1-e { background-position: -32px -48px; }
|
428 |
+
.cmb_element .ui-icon-arrowthick-1-se { background-position: -48px -48px; }
|
429 |
+
.cmb_element .ui-icon-arrowthick-1-s { background-position: -64px -48px; }
|
430 |
+
.cmb_element .ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
|
431 |
+
.cmb_element .ui-icon-arrowthick-1-w { background-position: -96px -48px; }
|
432 |
+
.cmb_element .ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
|
433 |
+
.cmb_element .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
|
434 |
+
.cmb_element .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
|
435 |
+
.cmb_element .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
|
436 |
+
.cmb_element .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
|
437 |
+
.cmb_element .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
|
438 |
+
.cmb_element .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
|
439 |
+
.cmb_element .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
|
440 |
+
.cmb_element .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
|
441 |
+
.cmb_element .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
|
442 |
+
.cmb_element .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
|
443 |
+
.cmb_element .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
|
444 |
+
.cmb_element .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
|
445 |
+
.cmb_element .ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
|
446 |
+
.cmb_element .ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
|
447 |
+
.cmb_element .ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
|
448 |
+
.cmb_element .ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
|
449 |
+
.cmb_element .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
|
450 |
+
.cmb_element .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
|
451 |
+
.cmb_element .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
|
452 |
+
.cmb_element .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
|
453 |
+
.cmb_element .ui-icon-arrow-4 { background-position: 0 -80px; }
|
454 |
+
.cmb_element .ui-icon-arrow-4-diag { background-position: -16px -80px; }
|
455 |
+
.cmb_element .ui-icon-extlink { background-position: -32px -80px; }
|
456 |
+
.cmb_element .ui-icon-newwin { background-position: -48px -80px; }
|
457 |
+
.cmb_element .ui-icon-refresh { background-position: -64px -80px; }
|
458 |
+
.cmb_element .ui-icon-shuffle { background-position: -80px -80px; }
|
459 |
+
.cmb_element .ui-icon-transfer-e-w { background-position: -96px -80px; }
|
460 |
+
.cmb_element .ui-icon-transferthick-e-w { background-position: -112px -80px; }
|
461 |
+
.cmb_element .ui-icon-folder-collapsed { background-position: 0 -96px; }
|
462 |
+
.cmb_element .ui-icon-folder-open { background-position: -16px -96px; }
|
463 |
+
.cmb_element .ui-icon-document { background-position: -32px -96px; }
|
464 |
+
.cmb_element .ui-icon-document-b { background-position: -48px -96px; }
|
465 |
+
.cmb_element .ui-icon-note { background-position: -64px -96px; }
|
466 |
+
.cmb_element .ui-icon-mail-closed { background-position: -80px -96px; }
|
467 |
+
.cmb_element .ui-icon-mail-open { background-position: -96px -96px; }
|
468 |
+
.cmb_element .ui-icon-suitcase { background-position: -112px -96px; }
|
469 |
+
.cmb_element .ui-icon-comment { background-position: -128px -96px; }
|
470 |
+
.cmb_element .ui-icon-person { background-position: -144px -96px; }
|
471 |
+
.cmb_element .ui-icon-print { background-position: -160px -96px; }
|
472 |
+
.cmb_element .ui-icon-trash { background-position: -176px -96px; }
|
473 |
+
.cmb_element .ui-icon-locked { background-position: -192px -96px; }
|
474 |
+
.cmb_element .ui-icon-unlocked { background-position: -208px -96px; }
|
475 |
+
.cmb_element .ui-icon-bookmark { background-position: -224px -96px; }
|
476 |
+
.cmb_element .ui-icon-tag { background-position: -240px -96px; }
|
477 |
+
.cmb_element .ui-icon-home { background-position: 0 -112px; }
|
478 |
+
.cmb_element .ui-icon-flag { background-position: -16px -112px; }
|
479 |
+
.cmb_element .ui-icon-calendar { background-position: -32px -112px; }
|
480 |
+
.cmb_element .ui-icon-cart { background-position: -48px -112px; }
|
481 |
+
.cmb_element .ui-icon-pencil { background-position: -64px -112px; }
|
482 |
+
.cmb_element .ui-icon-clock { background-position: -80px -112px; }
|
483 |
+
.cmb_element .ui-icon-disk { background-position: -96px -112px; }
|
484 |
+
.cmb_element .ui-icon-calculator { background-position: -112px -112px; }
|
485 |
+
.cmb_element .ui-icon-zoomin { background-position: -128px -112px; }
|
486 |
+
.cmb_element .ui-icon-zoomout { background-position: -144px -112px; }
|
487 |
+
.cmb_element .ui-icon-search { background-position: -160px -112px; }
|
488 |
+
.cmb_element .ui-icon-wrench { background-position: -176px -112px; }
|
489 |
+
.cmb_element .ui-icon-gear { background-position: -192px -112px; }
|
490 |
+
.cmb_element .ui-icon-heart { background-position: -208px -112px; }
|
491 |
+
.cmb_element .ui-icon-star { background-position: -224px -112px; }
|
492 |
+
.cmb_element .ui-icon-link { background-position: -240px -112px; }
|
493 |
+
.cmb_element .ui-icon-cancel { background-position: 0 -128px; }
|
494 |
+
.cmb_element .ui-icon-plus { background-position: -16px -128px; }
|
495 |
+
.cmb_element .ui-icon-plusthick { background-position: -32px -128px; }
|
496 |
+
.cmb_element .ui-icon-minus { background-position: -48px -128px; }
|
497 |
+
.cmb_element .ui-icon-minusthick { background-position: -64px -128px; }
|
498 |
+
.cmb_element .ui-icon-close { background-position: -80px -128px; }
|
499 |
+
.cmb_element .ui-icon-closethick { background-position: -96px -128px; }
|
500 |
+
.cmb_element .ui-icon-key { background-position: -112px -128px; }
|
501 |
+
.cmb_element .ui-icon-lightbulb { background-position: -128px -128px; }
|
502 |
+
.cmb_element .ui-icon-scissors { background-position: -144px -128px; }
|
503 |
+
.cmb_element .ui-icon-clipboard { background-position: -160px -128px; }
|
504 |
+
.cmb_element .ui-icon-copy { background-position: -176px -128px; }
|
505 |
+
.cmb_element .ui-icon-contact { background-position: -192px -128px; }
|
506 |
+
.cmb_element .ui-icon-image { background-position: -208px -128px; }
|
507 |
+
.cmb_element .ui-icon-video { background-position: -224px -128px; }
|
508 |
+
.cmb_element .ui-icon-script { background-position: -240px -128px; }
|
509 |
+
.cmb_element .ui-icon-alert { background-position: 0 -144px; }
|
510 |
+
.cmb_element .ui-icon-info { background-position: -16px -144px; }
|
511 |
+
.cmb_element .ui-icon-notice { background-position: -32px -144px; }
|
512 |
+
.cmb_element .ui-icon-help { background-position: -48px -144px; }
|
513 |
+
.cmb_element .ui-icon-check { background-position: -64px -144px; }
|
514 |
+
.cmb_element .ui-icon-bullet { background-position: -80px -144px; }
|
515 |
+
.cmb_element .ui-icon-radio-off { background-position: -96px -144px; }
|
516 |
+
.cmb_element .ui-icon-radio-on { background-position: -112px -144px; }
|
517 |
+
.cmb_element .ui-icon-pin-w { background-position: -128px -144px; }
|
518 |
+
.cmb_element .ui-icon-pin-s { background-position: -144px -144px; }
|
519 |
+
.cmb_element .ui-icon-play { background-position: 0 -160px; }
|
520 |
+
.cmb_element .ui-icon-pause { background-position: -16px -160px; }
|
521 |
+
.cmb_element .ui-icon-seek-next { background-position: -32px -160px; }
|
522 |
+
.cmb_element .ui-icon-seek-prev { background-position: -48px -160px; }
|
523 |
+
.cmb_element .ui-icon-seek-end { background-position: -64px -160px; }
|
524 |
+
.cmb_element .ui-icon-seek-start { background-position: -80px -160px; }
|
525 |
+
.cmb_element .ui-icon-seek-first { background-position: -80px -160px; }
|
526 |
+
.cmb_element .ui-icon-stop { background-position: -96px -160px; }
|
527 |
+
.cmb_element .ui-icon-eject { background-position: -112px -160px; }
|
528 |
+
.cmb_element .ui-icon-volume-off { background-position: -128px -160px; }
|
529 |
+
.cmb_element .ui-icon-volume-on { background-position: -144px -160px; }
|
530 |
+
.cmb_element .ui-icon-power { background-position: 0 -176px; }
|
531 |
+
.cmb_element .ui-icon-signal-diag { background-position: -16px -176px; }
|
532 |
+
.cmb_element .ui-icon-signal { background-position: -32px -176px; }
|
533 |
+
.cmb_element .ui-icon-battery-0 { background-position: -48px -176px; }
|
534 |
+
.cmb_element .ui-icon-battery-1 { background-position: -64px -176px; }
|
535 |
+
.cmb_element .ui-icon-battery-2 { background-position: -80px -176px; }
|
536 |
+
.cmb_element .ui-icon-battery-3 { background-position: -96px -176px; }
|
537 |
+
.cmb_element .ui-icon-circle-plus { background-position: 0 -192px; }
|
538 |
+
.cmb_element .ui-icon-circle-minus { background-position: -16px -192px; }
|
539 |
+
.cmb_element .ui-icon-circle-close { background-position: -32px -192px; }
|
540 |
+
.cmb_element .ui-icon-circle-triangle-e { background-position: -48px -192px; }
|
541 |
+
.cmb_element .ui-icon-circle-triangle-s { background-position: -64px -192px; }
|
542 |
+
.cmb_element .ui-icon-circle-triangle-w { background-position: -80px -192px; }
|
543 |
+
.cmb_element .ui-icon-circle-triangle-n { background-position: -96px -192px; }
|
544 |
+
.cmb_element .ui-icon-circle-arrow-e { background-position: -112px -192px; }
|
545 |
+
.cmb_element .ui-icon-circle-arrow-s { background-position: -128px -192px; }
|
546 |
+
.cmb_element .ui-icon-circle-arrow-w { background-position: -144px -192px; }
|
547 |
+
.cmb_element .ui-icon-circle-arrow-n { background-position: -160px -192px; }
|
548 |
+
.cmb_element .ui-icon-circle-zoomin { background-position: -176px -192px; }
|
549 |
+
.cmb_element .ui-icon-circle-zoomout { background-position: -192px -192px; }
|
550 |
+
.cmb_element .ui-icon-circle-check { background-position: -208px -192px; }
|
551 |
+
.cmb_element .ui-icon-circlesmall-plus { background-position: 0 -208px; }
|
552 |
+
.cmb_element .ui-icon-circlesmall-minus { background-position: -16px -208px; }
|
553 |
+
.cmb_element .ui-icon-circlesmall-close { background-position: -32px -208px; }
|
554 |
+
.cmb_element .ui-icon-squaresmall-plus { background-position: -48px -208px; }
|
555 |
+
.cmb_element .ui-icon-squaresmall-minus { background-position: -64px -208px; }
|
556 |
+
.cmb_element .ui-icon-squaresmall-close { background-position: -80px -208px; }
|
557 |
+
.cmb_element .ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
|
558 |
+
.cmb_element .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
|
559 |
+
.cmb_element .ui-icon-grip-solid-vertical { background-position: -32px -224px; }
|
560 |
+
.cmb_element .ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
|
561 |
+
.cmb_element .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
|
562 |
+
.cmb_element .ui-icon-grip-diagonal-se { background-position: -80px -224px; }
|
563 |
+
.cmb_element .ui-corner-all, .cmb_element .ui-corner-top, .cmb_element .ui-corner-left, .cmb_element .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
|
564 |
+
.cmb_element .ui-corner-all, .cmb_element .ui-corner-top, .cmb_element .ui-corner-right, .cmb_element .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
|
565 |
+
.cmb_element .ui-corner-all, .cmb_element .ui-corner-bottom, .cmb_element .ui-corner-left, .cmb_element .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
|
566 |
+
.cmb_element .ui-corner-all, .cmb_element .ui-corner-bottom, .cmb_element .ui-corner-right, .cmb_element .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
|
567 |
+
.cmb_element .ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
|
568 |
+
.cmb_element .ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }
|
569 |
+
.cmb_element .ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
|
570 |
+
.cmb_element .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
|
571 |
+
.cmb_element .ui-datepicker .ui-datepicker-prev, .cmb_element .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
|
572 |
+
.cmb_element .ui-datepicker .ui-datepicker-prev-hover, .cmb_element .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
|
573 |
+
.cmb_element .ui-datepicker .ui-datepicker-prev { left:2px; }
|
574 |
+
.cmb_element .ui-datepicker .ui-datepicker-next { right:2px; }
|
575 |
+
.cmb_element .ui-datepicker .ui-datepicker-prev-hover { left:1px; }
|
576 |
+
.cmb_element .ui-datepicker .ui-datepicker-next-hover { right:1px; }
|
577 |
+
.cmb_element .ui-datepicker .ui-datepicker-prev span, .cmb_element .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
|
578 |
+
.cmb_element .ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
|
579 |
+
.cmb_element .ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
|
580 |
+
.cmb_element .ui-datepicker select.ui-datepicker-month-year {width: 100%;}
|
581 |
+
.cmb_element .ui-datepicker select.ui-datepicker-month,
|
582 |
+
.cmb_element .ui-datepicker select.ui-datepicker-year { width: 49%;}
|
583 |
+
.cmb_element .ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
|
584 |
+
.cmb_element .ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
|
585 |
+
.cmb_element .ui-datepicker td { border: 0; padding: 1px; }
|
586 |
+
.cmb_element .ui-datepicker td span, .cmb_element .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
|
587 |
+
.cmb_element .ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
|
588 |
+
.cmb_element .ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
|
589 |
+
.cmb_element .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
|
590 |
+
.cmb_element .ui-datepicker.ui-datepicker-multi { width:auto; }
|
591 |
+
.cmb_element .ui-datepicker-multi .ui-datepicker-group { float:left; }
|
592 |
+
.cmb_element .ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
|
593 |
+
.cmb_element .ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
|
594 |
+
.cmb_element .ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
|
595 |
+
.cmb_element .ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
|
596 |
+
.cmb_element .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
|
597 |
+
.cmb_element .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
|
598 |
+
.cmb_element .ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
|
599 |
+
.cmb_element .ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
|
600 |
+
.cmb_element .ui-datepicker-rtl { direction: rtl; }
|
601 |
+
.cmb_element .ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
|
602 |
+
.cmb_element .ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
|
603 |
+
.cmb_element .ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
|
604 |
+
.cmb_element .ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
|
605 |
+
.cmb_element .ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
|
606 |
+
.cmb_element .ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
|
607 |
+
.cmb_element .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
|
608 |
+
.cmb_element .ui-datepicker-rtl .ui-datepicker-group { float:right; }
|
609 |
+
.cmb_element .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
|
610 |
+
.cmb_element .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
|
611 |
+
.cmb_element .ui-datepicker-cover {
|
612 |
+
display: none; /*sorry for IE5*/
|
613 |
+
display/**/: block; /*sorry for IE5*/
|
614 |
+
position: absolute; /*must have*/
|
615 |
+
z-index: -1; /*must have*/
|
616 |
+
filter: mask(); /*must have*/
|
617 |
+
top: -4px; /*must have*/
|
618 |
+
left: -4px; /*must have*/
|
619 |
+
width: 200px; /*must have*/
|
620 |
+
height: 200px; /*must have*/
|
621 |
+
}
|
lib/support-contact-form.php
CHANGED
@@ -1,49 +1,49 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( isset( $_REQUEST['action'] ) ) {
|
4 |
-
$action=$_REQUEST['action'];
|
5 |
-
}
|
6 |
-
|
7 |
-
if ( !isset( $action ) ) /* display the contact form */ {
|
8 |
-
?>
|
9 |
-
<p><?php _e( 'If you need support, please fill out the following form. I will get back to you with some support as soon as possible.' , 'timeline-express' ); ?></p>
|
10 |
-
<p><em><?php _e( 'note: support requests are limited to one per hour, to help reduce spam.' , 'timeline-express' ); ?></em></p>
|
11 |
-
<form action="" method="POST" enctype="multipart/form-data">
|
12 |
-
<input type="hidden" name="action" value="submit">
|
13 |
-
<label for="name"><?php _e( 'Your name' , 'timeline-express' ); ?>: <br />
|
14 |
-
<input name="name" type="text" value="<?php echo $license_data->customer_name; ?>" size="30"/></label>
|
15 |
-
<label for="message"><?php _e( 'Your message' , 'timeline-express' ); ?>:<br>
|
16 |
-
<textarea name="message" rows="7" cols="30" placeholder="<?php _e( 'please describe your issue in as much detail as possible' , 'timeline-express' ); ?>"></textarea></label>
|
17 |
-
<input type="submit" class="button-primary" value="Get Spport"/>
|
18 |
-
</form>
|
19 |
-
<?php
|
20 |
-
} else /* send the submitted data */ {
|
21 |
-
$name = trim( $_REQUEST['name'] );
|
22 |
-
$email = $license_data->customer_email;
|
23 |
-
// append the users license key, and other data
|
24 |
-
$message = '<strong>License Key :</strong> ' . $license . '<br /><strong>Expires :</strong> ' . date( 'F jS, Y' , strtotime( $license_data->expires ) ) . ' <br /><br /> <strong>Support Issue :</strong><br />' . $_REQUEST['message'];
|
25 |
-
|
26 |
-
if ( ( $name=="" ) || ( $email=="" ) || ( $_REQUEST['message']=="" ) ) {
|
27 |
-
echo "All fields are required, please fill <a href=\"\">the form</a> again.";
|
28 |
-
} else {
|
29 |
-
$from="From: $name <$email>";
|
30 |
-
$content_type='Content-type: text/html';
|
31 |
-
$subject="Premium Support Request: Timeline Express";
|
32 |
-
$headers = array( $from , $content_type );
|
33 |
-
|
34 |
-
$email = wp_mail("evan.m.herman@gmail.com", $subject, $message, $headers);
|
35 |
-
|
36 |
-
if ( is_wp_error( $email ) ) {
|
37 |
-
echo '<p>' . __( 'There was an error sending your request' , 'timeline-express' ) . ' : ' . $email->get_error_message() . '</p>';
|
38 |
-
echo '<p>' . __( 'If the error persists, please contact me directly for support at' , 'timeline-express' ) . '<a href="mailto:Evan.M.Herman@gmail.com" title="Email Support">Evan.M.Herman@Gmail.com</a></p>';
|
39 |
-
} else {
|
40 |
-
if ( $email ) {
|
41 |
-
set_transient( 'timeline_express_support_request_sent', '1', 1 * HOUR_IN_SECONDS );
|
42 |
-
echo '<p>' . __( "Support request successfully sent. I will be in touch regarding your issue shortly." , "timeline-express" ) . '</p>';
|
43 |
-
}
|
44 |
-
}
|
45 |
-
|
46 |
-
|
47 |
-
}
|
48 |
-
}
|
49 |
?>
|
1 |
+
<?php
|
2 |
+
|
3 |
+
if ( isset( $_REQUEST['action'] ) ) {
|
4 |
+
$action=$_REQUEST['action'];
|
5 |
+
}
|
6 |
+
|
7 |
+
if ( !isset( $action ) ) /* display the contact form */ {
|
8 |
+
?>
|
9 |
+
<p><?php _e( 'If you need support, please fill out the following form. I will get back to you with some support as soon as possible.' , 'timeline-express' ); ?></p>
|
10 |
+
<p><em><?php _e( 'note: support requests are limited to one per hour, to help reduce spam.' , 'timeline-express' ); ?></em></p>
|
11 |
+
<form action="" method="POST" enctype="multipart/form-data">
|
12 |
+
<input type="hidden" name="action" value="submit">
|
13 |
+
<label for="name"><?php _e( 'Your name' , 'timeline-express' ); ?>: <br />
|
14 |
+
<input name="name" type="text" value="<?php echo $license_data->customer_name; ?>" size="30"/></label>
|
15 |
+
<label for="message"><?php _e( 'Your message' , 'timeline-express' ); ?>:<br>
|
16 |
+
<textarea name="message" rows="7" cols="30" placeholder="<?php _e( 'please describe your issue in as much detail as possible' , 'timeline-express' ); ?>"></textarea></label>
|
17 |
+
<input type="submit" class="button-primary" value="Get Spport"/>
|
18 |
+
</form>
|
19 |
+
<?php
|
20 |
+
} else /* send the submitted data */ {
|
21 |
+
$name = trim( $_REQUEST['name'] );
|
22 |
+
$email = $license_data->customer_email;
|
23 |
+
// append the users license key, and other data
|
24 |
+
$message = '<strong>License Key :</strong> ' . $license . '<br /><strong>Expires :</strong> ' . date( 'F jS, Y' , strtotime( $license_data->expires ) ) . ' <br /><br /> <strong>Support Issue :</strong><br />' . $_REQUEST['message'];
|
25 |
+
|
26 |
+
if ( ( $name=="" ) || ( $email=="" ) || ( $_REQUEST['message']=="" ) ) {
|
27 |
+
echo "All fields are required, please fill <a href=\"\">the form</a> again.";
|
28 |
+
} else {
|
29 |
+
$from="From: $name <$email>";
|
30 |
+
$content_type='Content-type: text/html';
|
31 |
+
$subject="Premium Support Request: Timeline Express";
|
32 |
+
$headers = array( $from , $content_type );
|
33 |
+
|
34 |
+
$email = wp_mail("evan.m.herman@gmail.com", $subject, $message, $headers);
|
35 |
+
|
36 |
+
if ( is_wp_error( $email ) ) {
|
37 |
+
echo '<p>' . __( 'There was an error sending your request' , 'timeline-express' ) . ' : ' . $email->get_error_message() . '</p>';
|
38 |
+
echo '<p>' . __( 'If the error persists, please contact me directly for support at' , 'timeline-express' ) . '<a href="mailto:Evan.M.Herman@gmail.com" title="Email Support">Evan.M.Herman@Gmail.com</a></p>';
|
39 |
+
} else {
|
40 |
+
if ( $email ) {
|
41 |
+
set_transient( 'timeline_express_support_request_sent', '1', 1 * HOUR_IN_SECONDS );
|
42 |
+
echo '<p>' . __( "Support request successfully sent. I will be in touch regarding your issue shortly." , "timeline-express" ) . '</p>';
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
|
47 |
+
}
|
48 |
+
}
|
49 |
?>
|
pages/support.php
CHANGED
@@ -1,208 +1,208 @@
|
|
1 |
-
<?php
|
2 |
-
/*
|
3 |
-
Premium support template
|
4 |
-
// to do - setup chron to check license status once a day
|
5 |
-
// double check if we can't move this all into it's own support class file
|
6 |
-
//
|
7 |
-
*/
|
8 |
-
wp_enqueue_style( 'slideshow-css' , TIMELINE_EXPRESS_URL . 'css/timeline-express-css3-slideshow.css' );
|
9 |
-
wp_register_script( 'slideshow-js' , TIMELINE_EXPRESS_URL . 'js/support/jquery.slides.min.js' , array( 'jquery' ) , 'all' );
|
10 |
-
wp_enqueue_script( 'slideshow-js' );
|
11 |
-
|
12 |
-
$review_images = scandir( TIMELINE_EXPRESS_PATH . 'images/support/reviews' );
|
13 |
-
$license = get_option( 'timeline_express_license_key' );
|
14 |
-
$status = get_option( 'timeline_express_license_status' );
|
15 |
-
$license_data = get_option( 'timeline_express_license_data' );
|
16 |
-
?>
|
17 |
-
|
18 |
-
<div id="timeline-express-support-page-wrap">
|
19 |
-
|
20 |
-
|
21 |
-
<section id="timeline-express-support-page-header">
|
22 |
-
|
23 |
-
<img src="<?php echo TIMELINE_EXPRESS_URL . 'images/support/timeline-express-logo-256.png'; ?>" title="Timeline Express Logo" class="te-logo" >
|
24 |
-
|
25 |
-
<section class="support-subhead">
|
26 |
-
<h1 style="margin:0 0 1.2em 0;font-size:25px;"><?php _e( 'Timeline Express Support' , 'timeline-express' ); ?></h1>
|
27 |
-
<?php if( false !== $license ) {
|
28 |
-
if( $status !== false && $status == 'valid' ) { ?>
|
29 |
-
<p style="font-weight:200;"><?php _e( 'Thank you for purchasing a support license!' , 'timeline-express' ); ?></p>
|
30 |
-
<p style="font-weight:200;"><?php _e( 'If you run into any issues, or need support, feel free to submit a support ticket via the contact form below.' , 'timeline-express' ); ?></p>
|
31 |
-
<?php } else { ?>
|
32 |
-
<p style="font-weight:200;">
|
33 |
-
<?php _e( 'Have a support request? Please consider ' , 'timeline-express' ); ?>
|
34 |
-
<a href="http://www.evan-herman.com/wordpress-plugin/timeline-express/" title="Purchase a Support License Now" target="_blank"><?php _e( 'purchasing ' , 'timeline-express' ); ?></a>
|
35 |
-
<?php _e( 'a support license.' , 'timeline-express' ); ?>
|
36 |
-
</p>
|
37 |
-
<p style="font-weight:200;"><?php _e( 'Your purchase will go towards the continued development and support of Timeline Express, so the plugin will continue to thrive and improve.' , 'timeline-express' ); ?></p>
|
38 |
-
<?php }
|
39 |
-
} ?>
|
40 |
-
|
41 |
-
<!-- if the user doesn't have a license key, lets display the slider -->
|
42 |
-
<?php if( false !== $license ) {
|
43 |
-
|
44 |
-
if( $status !== false && $status != 'valid' || $status == false ) { ?>
|
45 |
-
|
46 |
-
<div class="te-slider-container">
|
47 |
-
<div id="slides">
|
48 |
-
<?php
|
49 |
-
foreach( $review_images as $review ) {
|
50 |
-
if ( $review != '.' && $review != '..' ) {
|
51 |
-
echo '<img src="' . TIMELINE_EXPRESS_URL .'images/support/reviews/' . $review . '" alt="review" >';
|
52 |
-
}
|
53 |
-
}
|
54 |
-
?>
|
55 |
-
</div>
|
56 |
-
</div>
|
57 |
-
|
58 |
-
<?php
|
59 |
-
}
|
60 |
-
} ?>
|
61 |
-
|
62 |
-
</section>
|
63 |
-
|
64 |
-
</section>
|
65 |
-
|
66 |
-
<hr />
|
67 |
-
|
68 |
-
<form id="support-license-form" method="post" action="options.php">
|
69 |
-
|
70 |
-
<?php settings_fields('timeline_express_license'); ?>
|
71 |
-
|
72 |
-
<label for="timeline_express_license_key">
|
73 |
-
<strong><?php _e( 'Support License Key' , 'timeline-express' ); ?></strong>
|
74 |
-
|
75 |
-
<p style="display:inline-block;width:100%;">
|
76 |
-
|
77 |
-
<input id="timeline_express_license_key" type="text" placeholder="<?php _e( 'Support license key' , 'timeline-express' ); ?>" name="timeline_express_license_key" value="<?php esc_attr_e( $license ); ?>">
|
78 |
-
<?php if( false !== $license ) {
|
79 |
-
if( $status !== false && $status == 'valid' ) { $license_data = get_option( 'timeline_express_license_data' ); ?>
|
80 |
-
<span class="dashicons dashicons-yes timeline-express-valid-license" title="<?php _e( 'Valid and Active License' , 'timeline-express' ); ?>"></span>
|
81 |
-
<?php } else if ( $status !== false && $status == 'invalid' && $license_data->error == 'revoked' ) { // invalid status returned ?>
|
82 |
-
<a href="http://www.evan-herman.com/wordpress-plugin/timeline-express/" title="Purchase a Support License Now" target="_blank">
|
83 |
-
<input type="button" class="button-secondary purchase-support-license" value="<?php _e( 'Purchase a License' , 'timeline-express' ); ?>">
|
84 |
-
</a>
|
85 |
-
<section class="timeline-express-invalid-license-error"><span class="dashicons dashicons-no-alt"></span><?php echo __( 'There was an error with your license. It appears that your license key has been ' , 'timeline-express' ) . '<strong>' . $license_data->error . '</strong>' . '. ' . __( 'Please get in contact with support at ' , 'timeline-express' ); ?><a href="http://www.evan-herman.com/contact/" title="Evan Herman Plugin Development"><?php _e( 'EH Dev. Shop' , 'timeline-express' ); ?></a> <?php _e( ' to resolve the issue' , 'timeline-express' ); ?>.</section>
|
86 |
-
<?php } else if ( $status !== false && $status == 'invalid' && $license_data->error == 'missing' ) { // invalid api key...doesn't exist in the database, was never purchased. ?>
|
87 |
-
<a href="http://www.evan-herman.com/wordpress-plugin/timeline-express/" title="Purchase a Support License Now" target="_blank">
|
88 |
-
<input type="button" class="button-secondary purchase-support-license" value="<?php _e( 'Purchase a License' , 'timeline-express' ); ?>">
|
89 |
-
</a>
|
90 |
-
<section class="timeline-express-invalid-license-error"><span class="dashicons dashicons-no-alt"></span><?php echo __( 'Sorry this license key appears to be invalid. Please purchase a valid license key.' , 'timeline-express' ); ?></section>
|
91 |
-
<?php } else if ( $status !== false && $status == 'invalid' && $license_data->error == 'expired' || $status !== false && $status == 'expired' ) { // invalid api key...doesn't exist in the database, was never purchased. ?>
|
92 |
-
<a href="http://www.evan-herman.com/wordpress-plugin/timeline-express/" class="button-secondary purchase-support-license" alt="<?php esc_attr_e( $license ); ?>" title="<?php _e( 'Renew your Timeline Express license' , 'timeline-express' ); ?>" target="_blank">
|
93 |
-
<?php _e( 'Renew Your License' , 'timeline-express' ); ?>
|
94 |
-
</a>
|
95 |
-
<section class="timeline-express-invalid-license-error"><span class="dashicons dashicons-no-alt"></span><?php echo __( 'Oops, it looks like your license has expired. Please consider renewing your license for another year to continue receiving support.' , 'timeline-express' ); ?></section>
|
96 |
-
<?php } else { ?>
|
97 |
-
<a href="http://www.evan-herman.com/wordpress-plugin/timeline-express/" title="Purchase a Support License Now" target="_blank">
|
98 |
-
<input type="button" class="button-secondary purchase-support-license" value="<?php _e( 'Purchase a License' , 'timeline-express' ); ?>">
|
99 |
-
</a>
|
100 |
-
<?php
|
101 |
-
}
|
102 |
-
}
|
103 |
-
?>
|
104 |
-
</p>
|
105 |
-
|
106 |
-
</label>
|
107 |
-
|
108 |
-
<section class="timeline-express-license-buttons">
|
109 |
-
|
110 |
-
<input type="submit" class="button-primary" value="Save Changes" style="float:left; margin-right: 1em;">
|
111 |
-
|
112 |
-
<!-- when active key, display a support ticketing form -->
|
113 |
-
<?php if( false !== $license ) { ?>
|
114 |
-
<?php if( $status !== false && $status == 'valid' ) { $license_data = get_option( 'timeline_express_license_data' ); ?>
|
115 |
-
<?php wp_nonce_field( 'timeline_express_nonce', 'timeline_express_nonce' ); ?>
|
116 |
-
<input type="submit" class="button-secondary" name="timeline_express_license_deactivate" value="<?php _e('Deactivate License'); ?>"/>
|
117 |
-
<?php } else {
|
118 |
-
if ( $license != '' ) {
|
119 |
-
wp_nonce_field( 'timeline_express_nonce', 'timeline_express_nonce' ); ?>
|
120 |
-
<input type="submit" class="button-secondary" name="timeline_express_license_activate" value="<?php _e('Activate License'); ?>"/>
|
121 |
-
<?php } } ?>
|
122 |
-
<?php } ?>
|
123 |
-
|
124 |
-
</section>
|
125 |
-
|
126 |
-
</form>
|
127 |
-
|
128 |
-
<?php if( false !== $license ) {
|
129 |
-
|
130 |
-
if( $status !== false && $status == 'valid' ) {
|
131 |
-
|
132 |
-
$license_data = get_option( 'timeline_express_license_data' ); ?>
|
133 |
-
|
134 |
-
<hr style="margin-bottom:2.5em;" />
|
135 |
-
|
136 |
-
<div style="width:100%; display:inline-block;">
|
137 |
-
|
138 |
-
<table class="widefat fixed" cellspacing="0" style="width:100%;max-width:500px; float:right;">
|
139 |
-
<thead>
|
140 |
-
<tr>
|
141 |
-
<th id="columnname" class="manage-column column-columnname" scope="col"><?php _e( 'License Info.' , 'timeline-express' ); ?></th>
|
142 |
-
<th id="columnname" class="manage-column column-columnname num" scope="col"></th>
|
143 |
-
</tr>
|
144 |
-
</thead>
|
145 |
-
|
146 |
-
<tbody>
|
147 |
-
|
148 |
-
<tr class="alternate">
|
149 |
-
<td class="column-columnname"><b><?php _e( 'License Holder' , 'timeline-express' ); ?></b></td>
|
150 |
-
<td class="column-columnname" style="text-align:center;"><?php echo $license_data->customer_name; ?></td>
|
151 |
-
</tr>
|
152 |
-
|
153 |
-
<tr class="alternate">
|
154 |
-
<td class="column-columnname"><b><?php _e( 'Sites Active/Limit' , 'timeline-express' ); ?></b></td>
|
155 |
-
<td class="column-columnname" style="text-align:center;"><?php echo $license_data->site_count . '/' . $license_data->license_limit; ?></td>
|
156 |
-
</tr>
|
157 |
-
|
158 |
-
<tr>
|
159 |
-
<td class="column-columnname"><b><?php _e( 'License Expires' , 'timeline-express' ); ?></b></td>
|
160 |
-
<td class="column-columnname" style="text-align:center;"><?php echo date( 'F jS, Y' , strtotime( $license_data->expires ) ); $days_remaining = (strtotime( $license_data->expires ) - strtotime('now')) / (60 * 60 * 24); if ( round( $days_remaining ) < 30 ) { echo '<span class="license-expiring-soon">expiring soon</span>'; } ?></td>
|
161 |
-
</tr>
|
162 |
-
|
163 |
-
</tbody>
|
164 |
-
</table>
|
165 |
-
|
166 |
-
|
167 |
-
<section id="premium-support-contact-form">
|
168 |
-
<h2 style="margin-bottom:.5em;margin-top:0;"><?php _e( 'Premium Support Ticketing' , 'timeline-express' ); ?></h2>
|
169 |
-
<?php
|
170 |
-
// check if the user has sent a request in the past hour
|
171 |
-
if ( false === get_transient( 'timeline_express_support_request_sent' ) ) {
|
172 |
-
require_once TIMELINE_EXPRESS_PATH . 'lib/support-contact-form.php';
|
173 |
-
} else {
|
174 |
-
_e( "It looks like you have recently sent us a support request. We limit the number of support requests to 1 per hour, to avoid spam. Sorry for the inconvinience, and thank you for understanding." , "timeline-express" );
|
175 |
-
}
|
176 |
-
?>
|
177 |
-
</section>
|
178 |
-
|
179 |
-
</div>
|
180 |
-
|
181 |
-
<?php
|
182 |
-
}
|
183 |
-
}
|
184 |
-
?>
|
185 |
-
|
186 |
-
<section id="eh-logos" style="display:block;width:100%;text-align:right;">
|
187 |
-
<a href="http://www.evan-herman.com" target="_blank" title="Evan Herman Professional WordPress Development">
|
188 |
-
<img src="<?php echo TIMELINE_EXPRESS_URL; ?>images/evan_herman_logo.png" alt="Evan Herman Logo" style="margin-right:4.5em;"><br />
|
189 |
-
<img src="<?php echo TIMELINE_EXPRESS_URL; ?>images/evan-herman-mascot.png" alt="Evan Herman Mascot" style="width:300px;margin-top:1em;" >
|
190 |
-
</a>
|
191 |
-
</section>
|
192 |
-
|
193 |
-
</div>
|
194 |
-
|
195 |
-
<!-- initialize the slider :) -->
|
196 |
-
<script>
|
197 |
-
jQuery(function() {
|
198 |
-
jQuery('#slides').slidesjs({
|
199 |
-
height: 200,
|
200 |
-
play: {
|
201 |
-
active: true,
|
202 |
-
auto: true,
|
203 |
-
interval: 6000,
|
204 |
-
swap: true
|
205 |
-
}
|
206 |
-
});
|
207 |
-
});
|
208 |
</script>
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Premium support template
|
4 |
+
// to do - setup chron to check license status once a day
|
5 |
+
// double check if we can't move this all into it's own support class file
|
6 |
+
//
|
7 |
+
*/
|
8 |
+
wp_enqueue_style( 'slideshow-css' , TIMELINE_EXPRESS_URL . 'css/timeline-express-css3-slideshow.css' );
|
9 |
+
wp_register_script( 'slideshow-js' , TIMELINE_EXPRESS_URL . 'js/support/jquery.slides.min.js' , array( 'jquery' ) , 'all' );
|
10 |
+
wp_enqueue_script( 'slideshow-js' );
|
11 |
+
|
12 |
+
$review_images = scandir( TIMELINE_EXPRESS_PATH . 'images/support/reviews' );
|
13 |
+
$license = get_option( 'timeline_express_license_key' );
|
14 |
+
$status = get_option( 'timeline_express_license_status' );
|
15 |
+
$license_data = get_option( 'timeline_express_license_data' );
|
16 |
+
?>
|
17 |
+
|
18 |
+
<div id="timeline-express-support-page-wrap">
|
19 |
+
|
20 |
+
|
21 |
+
<section id="timeline-express-support-page-header">
|
22 |
+
|
23 |
+
<img src="<?php echo TIMELINE_EXPRESS_URL . 'images/support/timeline-express-logo-256.png'; ?>" title="Timeline Express Logo" class="te-logo" >
|
24 |
+
|
25 |
+
<section class="support-subhead">
|
26 |
+
<h1 style="margin:0 0 1.2em 0;font-size:25px;"><?php _e( 'Timeline Express Support' , 'timeline-express' ); ?></h1>
|
27 |
+
<?php if( false !== $license ) {
|
28 |
+
if( $status !== false && $status == 'valid' ) { ?>
|
29 |
+
<p style="font-weight:200;"><?php _e( 'Thank you for purchasing a support license!' , 'timeline-express' ); ?></p>
|
30 |
+
<p style="font-weight:200;"><?php _e( 'If you run into any issues, or need support, feel free to submit a support ticket via the contact form below.' , 'timeline-express' ); ?></p>
|
31 |
+
<?php } else { ?>
|
32 |
+
<p style="font-weight:200;">
|
33 |
+
<?php _e( 'Have a support request? Please consider ' , 'timeline-express' ); ?>
|
34 |
+
<a href="http://www.evan-herman.com/wordpress-plugin/timeline-express/" title="Purchase a Support License Now" target="_blank"><?php _e( 'purchasing ' , 'timeline-express' ); ?></a>
|
35 |
+
<?php _e( 'a support license.' , 'timeline-express' ); ?>
|
36 |
+
</p>
|
37 |
+
<p style="font-weight:200;"><?php _e( 'Your purchase will go towards the continued development and support of Timeline Express, so the plugin will continue to thrive and improve.' , 'timeline-express' ); ?></p>
|
38 |
+
<?php }
|
39 |
+
} ?>
|
40 |
+
|
41 |
+
<!-- if the user doesn't have a license key, lets display the slider -->
|
42 |
+
<?php if( false !== $license ) {
|
43 |
+
|
44 |
+
if( $status !== false && $status != 'valid' || $status == false ) { ?>
|
45 |
+
|
46 |
+
<div class="te-slider-container">
|
47 |
+
<div id="slides">
|
48 |
+
<?php
|
49 |
+
foreach( $review_images as $review ) {
|
50 |
+
if ( $review != '.' && $review != '..' ) {
|
51 |
+
echo '<img src="' . TIMELINE_EXPRESS_URL .'images/support/reviews/' . $review . '" alt="review" >';
|
52 |
+
}
|
53 |
+
}
|
54 |
+
?>
|
55 |
+
</div>
|
56 |
+
</div>
|
57 |
+
|
58 |
+
<?php
|
59 |
+
}
|
60 |
+
} ?>
|
61 |
+
|
62 |
+
</section>
|
63 |
+
|
64 |
+
</section>
|
65 |
+
|
66 |
+
<hr />
|
67 |
+
|
68 |
+
<form id="support-license-form" method="post" action="options.php">
|
69 |
+
|
70 |
+
<?php settings_fields('timeline_express_license'); ?>
|
71 |
+
|
72 |
+
<label for="timeline_express_license_key">
|
73 |
+
<strong><?php _e( 'Support License Key' , 'timeline-express' ); ?></strong>
|
74 |
+
|
75 |
+
<p style="display:inline-block;width:100%;">
|
76 |
+
|
77 |
+
<input id="timeline_express_license_key" type="text" placeholder="<?php _e( 'Support license key' , 'timeline-express' ); ?>" name="timeline_express_license_key" value="<?php esc_attr_e( $license ); ?>">
|
78 |
+
<?php if( false !== $license ) {
|
79 |
+
if( $status !== false && $status == 'valid' ) { $license_data = get_option( 'timeline_express_license_data' ); ?>
|
80 |
+
<span class="dashicons dashicons-yes timeline-express-valid-license" title="<?php _e( 'Valid and Active License' , 'timeline-express' ); ?>"></span>
|
81 |
+
<?php } else if ( $status !== false && $status == 'invalid' && $license_data->error == 'revoked' ) { // invalid status returned ?>
|
82 |
+
<a href="http://www.evan-herman.com/wordpress-plugin/timeline-express/" title="Purchase a Support License Now" target="_blank">
|
83 |
+
<input type="button" class="button-secondary purchase-support-license" value="<?php _e( 'Purchase a License' , 'timeline-express' ); ?>">
|
84 |
+
</a>
|
85 |
+
<section class="timeline-express-invalid-license-error"><span class="dashicons dashicons-no-alt"></span><?php echo __( 'There was an error with your license. It appears that your license key has been ' , 'timeline-express' ) . '<strong>' . $license_data->error . '</strong>' . '. ' . __( 'Please get in contact with support at ' , 'timeline-express' ); ?><a href="http://www.evan-herman.com/contact/" title="Evan Herman Plugin Development"><?php _e( 'EH Dev. Shop' , 'timeline-express' ); ?></a> <?php _e( ' to resolve the issue' , 'timeline-express' ); ?>.</section>
|
86 |
+
<?php } else if ( $status !== false && $status == 'invalid' && $license_data->error == 'missing' ) { // invalid api key...doesn't exist in the database, was never purchased. ?>
|
87 |
+
<a href="http://www.evan-herman.com/wordpress-plugin/timeline-express/" title="Purchase a Support License Now" target="_blank">
|
88 |
+
<input type="button" class="button-secondary purchase-support-license" value="<?php _e( 'Purchase a License' , 'timeline-express' ); ?>">
|
89 |
+
</a>
|
90 |
+
<section class="timeline-express-invalid-license-error"><span class="dashicons dashicons-no-alt"></span><?php echo __( 'Sorry this license key appears to be invalid. Please purchase a valid license key.' , 'timeline-express' ); ?></section>
|
91 |
+
<?php } else if ( $status !== false && $status == 'invalid' && $license_data->error == 'expired' || $status !== false && $status == 'expired' ) { // invalid api key...doesn't exist in the database, was never purchased. ?>
|
92 |
+
<a href="http://www.evan-herman.com/wordpress-plugin/timeline-express/" class="button-secondary purchase-support-license" alt="<?php esc_attr_e( $license ); ?>" title="<?php _e( 'Renew your Timeline Express license' , 'timeline-express' ); ?>" target="_blank">
|
93 |
+
<?php _e( 'Renew Your License' , 'timeline-express' ); ?>
|
94 |
+
</a>
|
95 |
+
<section class="timeline-express-invalid-license-error"><span class="dashicons dashicons-no-alt"></span><?php echo __( 'Oops, it looks like your license has expired. Please consider renewing your license for another year to continue receiving support.' , 'timeline-express' ); ?></section>
|
96 |
+
<?php } else { ?>
|
97 |
+
<a href="http://www.evan-herman.com/wordpress-plugin/timeline-express/" title="Purchase a Support License Now" target="_blank">
|
98 |
+
<input type="button" class="button-secondary purchase-support-license" value="<?php _e( 'Purchase a License' , 'timeline-express' ); ?>">
|
99 |
+
</a>
|
100 |
+
<?php
|
101 |
+
}
|
102 |
+
}
|
103 |
+
?>
|
104 |
+
</p>
|
105 |
+
|
106 |
+
</label>
|
107 |
+
|
108 |
+
<section class="timeline-express-license-buttons">
|
109 |
+
|
110 |
+
<input type="submit" class="button-primary" value="Save Changes" style="float:left; margin-right: 1em;">
|
111 |
+
|
112 |
+
<!-- when active key, display a support ticketing form -->
|
113 |
+
<?php if( false !== $license ) { ?>
|
114 |
+
<?php if( $status !== false && $status == 'valid' ) { $license_data = get_option( 'timeline_express_license_data' ); ?>
|
115 |
+
<?php wp_nonce_field( 'timeline_express_nonce', 'timeline_express_nonce' ); ?>
|
116 |
+
<input type="submit" class="button-secondary" name="timeline_express_license_deactivate" value="<?php _e('Deactivate License'); ?>"/>
|
117 |
+
<?php } else {
|
118 |
+
if ( $license != '' ) {
|
119 |
+
wp_nonce_field( 'timeline_express_nonce', 'timeline_express_nonce' ); ?>
|
120 |
+
<input type="submit" class="button-secondary" name="timeline_express_license_activate" value="<?php _e('Activate License'); ?>"/>
|
121 |
+
<?php } } ?>
|
122 |
+
<?php } ?>
|
123 |
+
|
124 |
+
</section>
|
125 |
+
|
126 |
+
</form>
|
127 |
+
|
128 |
+
<?php if( false !== $license ) {
|
129 |
+
|
130 |
+
if( $status !== false && $status == 'valid' ) {
|
131 |
+
|
132 |
+
$license_data = get_option( 'timeline_express_license_data' ); ?>
|
133 |
+
|
134 |
+
<hr style="margin-bottom:2.5em;" />
|
135 |
+
|
136 |
+
<div style="width:100%; display:inline-block;">
|
137 |
+
|
138 |
+
<table class="widefat fixed" cellspacing="0" style="width:100%;max-width:500px; float:right;">
|
139 |
+
<thead>
|
140 |
+
<tr>
|
141 |
+
<th id="columnname" class="manage-column column-columnname" scope="col"><?php _e( 'License Info.' , 'timeline-express' ); ?></th>
|
142 |
+
<th id="columnname" class="manage-column column-columnname num" scope="col"></th>
|
143 |
+
</tr>
|
144 |
+
</thead>
|
145 |
+
|
146 |
+
<tbody>
|
147 |
+
|
148 |
+
<tr class="alternate">
|
149 |
+
<td class="column-columnname"><b><?php _e( 'License Holder' , 'timeline-express' ); ?></b></td>
|
150 |
+
<td class="column-columnname" style="text-align:center;"><?php echo $license_data->customer_name; ?></td>
|
151 |
+
</tr>
|
152 |
+
|
153 |
+
<tr class="alternate">
|
154 |
+
<td class="column-columnname"><b><?php _e( 'Sites Active/Limit' , 'timeline-express' ); ?></b></td>
|
155 |
+
<td class="column-columnname" style="text-align:center;"><?php echo $license_data->site_count . '/' . $license_data->license_limit; ?></td>
|
156 |
+
</tr>
|
157 |
+
|
158 |
+
<tr>
|
159 |
+
<td class="column-columnname"><b><?php _e( 'License Expires' , 'timeline-express' ); ?></b></td>
|
160 |
+
<td class="column-columnname" style="text-align:center;"><?php echo date( 'F jS, Y' , strtotime( $license_data->expires ) ); $days_remaining = (strtotime( $license_data->expires ) - strtotime('now')) / (60 * 60 * 24); if ( round( $days_remaining ) < 30 ) { echo '<span class="license-expiring-soon">expiring soon</span>'; } ?></td>
|
161 |
+
</tr>
|
162 |
+
|
163 |
+
</tbody>
|
164 |
+
</table>
|
165 |
+
|
166 |
+
|
167 |
+
<section id="premium-support-contact-form">
|
168 |
+
<h2 style="margin-bottom:.5em;margin-top:0;"><?php _e( 'Premium Support Ticketing' , 'timeline-express' ); ?></h2>
|
169 |
+
<?php
|
170 |
+
// check if the user has sent a request in the past hour
|
171 |
+
if ( false === get_transient( 'timeline_express_support_request_sent' ) ) {
|
172 |
+
require_once TIMELINE_EXPRESS_PATH . 'lib/support-contact-form.php';
|
173 |
+
} else {
|
174 |
+
_e( "It looks like you have recently sent us a support request. We limit the number of support requests to 1 per hour, to avoid spam. Sorry for the inconvinience, and thank you for understanding." , "timeline-express" );
|
175 |
+
}
|
176 |
+
?>
|
177 |
+
</section>
|
178 |
+
|
179 |
+
</div>
|
180 |
+
|
181 |
+
<?php
|
182 |
+
}
|
183 |
+
}
|
184 |
+
?>
|
185 |
+
|
186 |
+
<section id="eh-logos" style="display:block;width:100%;text-align:right;">
|
187 |
+
<a href="http://www.evan-herman.com" target="_blank" title="Evan Herman Professional WordPress Development">
|
188 |
+
<img src="<?php echo TIMELINE_EXPRESS_URL; ?>images/evan_herman_logo.png" alt="Evan Herman Logo" style="margin-right:4.5em;"><br />
|
189 |
+
<img src="<?php echo TIMELINE_EXPRESS_URL; ?>images/evan-herman-mascot.png" alt="Evan Herman Mascot" style="width:300px;margin-top:1em;" >
|
190 |
+
</a>
|
191 |
+
</section>
|
192 |
+
|
193 |
+
</div>
|
194 |
+
|
195 |
+
<!-- initialize the slider :) -->
|
196 |
+
<script>
|
197 |
+
jQuery(function() {
|
198 |
+
jQuery('#slides').slidesjs({
|
199 |
+
height: 200,
|
200 |
+
play: {
|
201 |
+
active: true,
|
202 |
+
auto: true,
|
203 |
+
interval: 6000,
|
204 |
+
swap: true
|
205 |
+
}
|
206 |
+
});
|
207 |
+
});
|
208 |
</script>
|
pages/welcome.php
CHANGED
@@ -101,12 +101,12 @@ jQuery(document).ready(function() {
|
|
101 |
<div class="social-media-buttons" style="height:40px;">
|
102 |
<strong style="display:inline-block;float:left;margin-top:10px;font-size:16px;"><?php _e( 'Keep Up With Me Elsewhere ' , 'timeline-express' ); ?>:</strong>
|
103 |
<span style="display:inline-block;width:115px; margin-left:15px;margin-top:5px;">
|
104 |
-
<a href="https://profiles.wordpress.org/eherman24#content-plugins" title="WordPress" target="_blank" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL;
|
105 |
-
<a href="http://twitter.com/evanmherman" title="Twitter" target="_blank" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL;
|
106 |
-
<a href="https://www.linkedin.com/profile/view?id=46246110" title="Linkedin" target="_blank" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL;
|
107 |
-
<a href="http://www.evan-herman.com/feed/" title="RSS Feed" target="_blank" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL;
|
108 |
</span>
|
109 |
-
<a style="float:right;" href="http://www.evan-herman.com" title="EH Development Shop" target="_blank"><img src="<?php echo TIMELINE_EXPRESS_URL;
|
110 |
</div>
|
111 |
|
112 |
|
101 |
<div class="social-media-buttons" style="height:40px;">
|
102 |
<strong style="display:inline-block;float:left;margin-top:10px;font-size:16px;"><?php _e( 'Keep Up With Me Elsewhere ' , 'timeline-express' ); ?>:</strong>
|
103 |
<span style="display:inline-block;width:115px; margin-left:15px;margin-top:5px;">
|
104 |
+
<a href="https://profiles.wordpress.org/eherman24#content-plugins" title="WordPress" target="_blank" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL; ?>images/wordpress-icon.png" style="border: 0px none;" alt="Evan Herman - WordPress Profile" height="24" width="24"></a>
|
105 |
+
<a href="http://twitter.com/evanmherman" title="Twitter" target="_blank" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL; ?>images/twitter.png" style="border: 0px none;" alt="Evan Herman - Twitter Profile" height="24" width="24"></a>
|
106 |
+
<a href="https://www.linkedin.com/profile/view?id=46246110" title="Linkedin" target="_blank" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL; ?>images/linkedin.png" alt="Evan Herman - LinkedIn Profile" border="0" height="24" width="24"></a>
|
107 |
+
<a href="http://www.evan-herman.com/feed/" title="RSS Feed" target="_blank" class="evan_herman_about_icon"><img src="<?php echo TIMELINE_EXPRESS_URL; ?>images/rss_icon.png" alt="Evan Herman - RSS Feed" border="0" height="24" width="24"></a>
|
108 |
</span>
|
109 |
+
<a style="float:right;" href="http://www.evan-herman.com" title="EH Development Shop" target="_blank"><img src="<?php echo TIMELINE_EXPRESS_URL; ?>images/evan_herman_logo.png" alt="Evan Herman" class="timeline_express_header_logo" /></a>
|
110 |
</div>
|
111 |
|
112 |
|
readme.txt
CHANGED
@@ -4,7 +4,7 @@ Donate link: http://www.evan-herman.com/contact/?contact-reason=I%20want%20to%20
|
|
4 |
Tags: vertical, timeline, animated, css3, animations, evan, herman, evan herman, easy, time, line, font awesome, font, awesome, announcements, notifications, simple, events, calendar, scroll, triggered, scrolling, animated, fade, in, fade in
|
5 |
Requires at least: 3.9
|
6 |
Tested up to: 4.2
|
7 |
-
Stable tag: 1.1.6.
|
8 |
License: GPLv2 or later
|
9 |
|
10 |
Timeline express allows you to create a beautiful vertical animated and responsive timeline of posts , without writing a single line of code. Sweet!
|
@@ -54,6 +54,7 @@ Timeline express comes ready for translation. I would love to get things transla
|
|
54 |
* Polish (pl_PL) - thanks goes to Kanios
|
55 |
* German (de_DE) - thanks goes to <a href="http://www.fairsoft.koeln" target="_blank">Martin Gerlach</a>
|
56 |
* French (fr_FR) - thanks goes to <a href="http://troisplus-et-aeliin-cosplay.fr/" target="_blank">Julien Lambert</a>
|
|
|
57 |
|
58 |
<em>We're always looking for polyglots to help with the translations. If you enjoy this plugin, speak multiple languages and want to contribute please <a href="http://www.evan-herman.com/contact/" target="_blank">contact me</a> about how you can help translate things so users around the world can benefit from this plugin.</em>
|
59 |
|
@@ -121,7 +122,6 @@ If you enjoy this plugin and want to contribute, I'm always looking for people t
|
|
121 |
* Hebrew
|
122 |
* Hindi
|
123 |
* Hong Kong
|
124 |
-
* Italian
|
125 |
* Japanese
|
126 |
* Korean
|
127 |
* Persian
|
@@ -148,6 +148,14 @@ Have an idea for a future release feature? I love hearing about new ideas! You c
|
|
148 |
|
149 |
**Hooks + Filters**
|
150 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
151 |
**Use Alternate Image Size For Announcements (New v1.1.5.5)**
|
152 |
|
153 |
By default Timeline Express generates a custom image size to use within the timeline. If you would like to use another image size, you can use the following filter.
|
@@ -330,6 +338,10 @@ add_filter( 'timeline_express_custom_template' , 'custom_timeline_express_templa
|
|
330 |
|
331 |
== Changelog ==
|
332 |
|
|
|
|
|
|
|
|
|
333 |
= 1.1.6.6 - April 1st, 2015 =
|
334 |
* Enhancement: reverted to older styles (v1.1.6.4 stylesheet)
|
335 |
|
4 |
Tags: vertical, timeline, animated, css3, animations, evan, herman, evan herman, easy, time, line, font awesome, font, awesome, announcements, notifications, simple, events, calendar, scroll, triggered, scrolling, animated, fade, in, fade in
|
5 |
Requires at least: 3.9
|
6 |
Tested up to: 4.2
|
7 |
+
Stable tag: 1.1.6.7
|
8 |
License: GPLv2 or later
|
9 |
|
10 |
Timeline express allows you to create a beautiful vertical animated and responsive timeline of posts , without writing a single line of code. Sweet!
|
54 |
* Polish (pl_PL) - thanks goes to Kanios
|
55 |
* German (de_DE) - thanks goes to <a href="http://www.fairsoft.koeln" target="_blank">Martin Gerlach</a>
|
56 |
* French (fr_FR) - thanks goes to <a href="http://troisplus-et-aeliin-cosplay.fr/" target="_blank">Julien Lambert</a>
|
57 |
+
* Italian (it_IT) - thanks goes to <a href="http://evalosapeva.com/" target="_blank">Eva Filoramo</a>
|
58 |
|
59 |
<em>We're always looking for polyglots to help with the translations. If you enjoy this plugin, speak multiple languages and want to contribute please <a href="http://www.evan-herman.com/contact/" target="_blank">contact me</a> about how you can help translate things so users around the world can benefit from this plugin.</em>
|
60 |
|
122 |
* Hebrew
|
123 |
* Hindi
|
124 |
* Hong Kong
|
|
|
125 |
* Japanese
|
126 |
* Korean
|
127 |
* Persian
|
148 |
|
149 |
**Hooks + Filters**
|
150 |
|
151 |
+
**Use Custom Images Instead of Font Awesome Icons (New v1.1.6.7)**
|
152 |
+
|
153 |
+
Users can now use the custom announcement image in place of the font awesome icons by using the following filter. Huge thanks to <a href="https://petenelson.com/">Pete Nelson</a> for the pull request and making this possible and available for everyone.
|
154 |
+
|
155 |
+
Filter - timeline-express-custom-icon-html
|
156 |
+
|
157 |
+
Example: https://gist.github.com/EvanHerman/6bbc8de82f34b4cb3c5c
|
158 |
+
|
159 |
**Use Alternate Image Size For Announcements (New v1.1.5.5)**
|
160 |
|
161 |
By default Timeline Express generates a custom image size to use within the timeline. If you would like to use another image size, you can use the following filter.
|
338 |
|
339 |
== Changelog ==
|
340 |
|
341 |
+
= 1.1.6.7 - May 4th, 2015 =
|
342 |
+
* Added new filter to allow for custom images to be used in place of font awesome icons (Props Pete Nelson)
|
343 |
+
* Added
|
344 |
+
|
345 |
= 1.1.6.6 - April 1st, 2015 =
|
346 |
* Enhancement: reverted to older styles (v1.1.6.4 stylesheet)
|
347 |
|
timeline-express.php
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
Plugin Name: Timeline Express
|
5 |
Plugin URI: http://www.evan-herman.com
|
6 |
Description: Create a beautiful vertical, CSS3 animated and responsive timeline in minutes flat without writing code.
|
7 |
-
Version: 1.1.6.
|
8 |
Author: Evan Herman
|
9 |
Author URI: http://www.evan-herman.com
|
10 |
License: GPL2
|
@@ -28,7 +28,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
28 |
#_________________________________________________ CONSTANTS
|
29 |
|
30 |
/** Configuration **/
|
31 |
-
if(!defined('TIMELINE_EXPRESS_VERSION_CURRENT')) define('TIMELINE_EXPRESS_VERSION_CURRENT', '1.1.6.
|
32 |
if(!defined('TIMELINE_EXPRESS_PATH')) define('TIMELINE_EXPRESS_PATH', plugin_dir_path( __FILE__ ));
|
33 |
if(!defined('TIMELINE_EXPRESS_URL')) define('TIMELINE_EXPRESS_URL', plugins_url('timeline-express/'));
|
34 |
if(!defined('TIMELINE_EXPRESS_URL_WP')) define('TIMELINE_EXPRESS_URL_WP', get_bloginfo('url'));
|
4 |
Plugin Name: Timeline Express
|
5 |
Plugin URI: http://www.evan-herman.com
|
6 |
Description: Create a beautiful vertical, CSS3 animated and responsive timeline in minutes flat without writing code.
|
7 |
+
Version: 1.1.6.7
|
8 |
Author: Evan Herman
|
9 |
Author URI: http://www.evan-herman.com
|
10 |
License: GPL2
|
28 |
#_________________________________________________ CONSTANTS
|
29 |
|
30 |
/** Configuration **/
|
31 |
+
if(!defined('TIMELINE_EXPRESS_VERSION_CURRENT')) define('TIMELINE_EXPRESS_VERSION_CURRENT', '1.1.6.7');
|
32 |
if(!defined('TIMELINE_EXPRESS_PATH')) define('TIMELINE_EXPRESS_PATH', plugin_dir_path( __FILE__ ));
|
33 |
if(!defined('TIMELINE_EXPRESS_URL')) define('TIMELINE_EXPRESS_URL', plugins_url('timeline-express/'));
|
34 |
if(!defined('TIMELINE_EXPRESS_URL_WP')) define('TIMELINE_EXPRESS_URL_WP', get_bloginfo('url'));
|