Bulk Delete - Version 3.0

Version Description

Download this release

Release Info

Developer sudar
Plugin Icon 128x128 Bulk Delete
Version 3.0
Comparing to
See all releases

Code changes from version 2.2.2 to 3.0

bulk-delete.php CHANGED
@@ -3,13 +3,14 @@
3
  Plugin Name: Bulk Delete
4
  Plugin Script: bulk-delete.php
5
  Plugin URI: http://sudarmuthu.com/wordpress/bulk-delete
6
- Description: Bulk delete posts from selected categories or tags. Use it with caution.
7
  Donate Link: http://sudarmuthu.com/if-you-wanna-thank-me
8
- Version: 2.2.2
9
  License: GPL
10
  Author: Sudar
11
  Author URI: http://sudarmuthu.com/
12
  Text Domain: bulk-delete
 
13
 
14
  === RELEASE NOTES ===
15
  2009-02-02 - v0.1 - first version
@@ -44,6 +45,9 @@ Text Domain: bulk-delete
44
  - Added Serbian translations
45
  2012-12-20 - v2.2.2 - (Dev time: 0.5 hour)
46
  - Removed unused wpdb->prepare() function calls
 
 
 
47
  */
48
 
49
  /* Copyright 2009 Sudar Muthu (email : sudar@sudarmuthu.com)
@@ -63,261 +67,108 @@ Text Domain: bulk-delete
63
  */
64
 
65
  /**
66
- * Request Handler
67
  */
68
-
69
- if (!function_exists('smbd_request_handler')) {
70
- function smbd_request_handler() {
71
- global $wpdb;
72
-
 
 
 
 
 
73
  // Load localization domain
74
- load_plugin_textdomain( 'bulk-delete', false, dirname(plugin_basename(__FILE__)) . '/languages' );
75
-
76
- if (isset($_POST['smbd_action'])) {
77
-
78
- $wp_query = new WP_Query;
79
- check_admin_referer( 'bulk-delete-posts');
80
-
81
- switch($_POST['smbd_action']) {
82
-
83
- case "bulk-delete-cats":
84
- // delete by cats
85
- $selected_cats = array_get($_POST, 'smbd_cats');
86
-
87
- if (array_get($_POST, 'smbd_cats_restrict', FALSE) == "true") {
88
- add_filter ('posts_where', 'smbd_cats_by_days');
89
- }
90
-
91
- $private = array_get($_POST, 'smbd_cats_private');
92
-
93
- if ($private == 'true') {
94
- $options = array('category__in'=>$selected_cats,'post_status'=>'private', 'post_type'=>'post');
95
- } else {
96
- $options = array('category__in'=>$selected_cats,'post_status'=>'publish', 'post_type'=>'post');
97
- }
98
-
99
- $limit_to = absint(array_get($_POST, 'smbd_cats_limits_to', 0));
100
-
101
- if ($limit_to > 0) {
102
- $options['showposts'] = $limit_to;
103
- } else {
104
- $options['nopaging'] = 'true';
105
- }
106
-
107
- $force_delete = array_get($_POST, 'smbd_cats_force_delete', 'false');
108
-
109
- if ($force_delete == 'true') {
110
- $force_delete = true;
111
- } else {
112
- $force_delete = false;
113
- }
114
-
115
- $posts = $wp_query->query($options);
116
- foreach ($posts as $post) {
117
- wp_delete_post($post->ID, $force_delete);
118
- }
119
-
120
- break;
121
-
122
- case "bulk-delete-tags":
123
- // delete by tags
124
- $selected_tags = array_get($_POST, 'smbd_tags');
125
- if (array_get($_POST, 'smbd_tags_restrict', 'false') == "true") {
126
- add_filter ('posts_where', 'smbd_tags_by_days');
127
- }
128
-
129
- $private = array_get($_POST, 'smbd_tags_private', 'false');
130
-
131
- if ($private == 'true') {
132
- $options = array('tag__in'=>$selected_tags,'post_status'=>'private', 'post_type'=>'post');
133
- } else {
134
- $options = array('tag__in'=>$selected_tags,'post_status'=>'publish', 'post_type'=>'post');
135
- }
136
-
137
- $limit_to = absint(array_get($_POST, 'smbd_tags_limits_to', 0));
138
-
139
- if ($limit_to > 0) {
140
- $options['showposts'] = $limit_to;
141
- } else {
142
- $options['nopaging'] = 'true';
143
- }
144
-
145
- $force_delete = array_get($_POST, 'smbd_tags_force_delete');
146
-
147
- if ($force_delete == 'true') {
148
- $force_delete = true;
149
- } else {
150
- $force_delete = false;
151
- }
152
-
153
- $posts = $wp_query->query($options);
154
-
155
- foreach ($posts as $post) {
156
- wp_delete_post($post->ID, $force_delete);
157
- }
158
-
159
- break;
160
-
161
- case "bulk-delete-taxs":
162
- // delete by taxs
163
- $selected_taxs = array_get($_POST, 'smbd_taxs');
164
-
165
- foreach ($selected_taxs as $selected_tax) {
166
- $postids = smbd_get_tax_post($selected_tax);
167
-
168
- if (array_get($_POST, 'smbd_taxs_restrict', 'false') == "true") {
169
- add_filter ('posts_where', 'smbd_taxs_by_days');
170
- }
171
-
172
- $private = array_get($_POST, 'smbd_taxs_private');
173
-
174
- if ($private == 'true') {
175
- $options = array('post__in'=>$postids,'post_status'=>'private', 'post_type'=>'post');
176
- } else {
177
- $options = array('post__in'=>$postids,'post_status'=>'publish', 'post_type'=>'post');
178
- }
179
-
180
- $limit_to = absint(array_get($_POST, 'smbd_taxs_limits_to', 0));
181
-
182
- if ($limit_to > 0) {
183
- $options['showposts'] = $limit_to;
184
- } else {
185
- $options['nopaging'] = 'true';
186
- }
187
-
188
- $force_delete = array_get($_POST, 'smbd_taxs_force_delete');
189
-
190
- if ($force_delete == 'true') {
191
- $force_delete = true;
192
- } else {
193
- $force_delete = false;
194
- }
195
-
196
- $posts = $wp_query->query($options);
197
- foreach ($posts as $post) {
198
- wp_delete_post($post->ID, $force_delete);
199
- }
200
- }
201
-
202
- break;
203
-
204
- case "bulk-delete-special":
205
- $options = array();
206
-
207
- $limit_to = absint(array_get($_POST, 'smbd_special_limit_to', 0));
208
-
209
- if ($limit_to > 0) {
210
- $options['showposts'] = $limit_to;
211
- } else {
212
- $options['nopaging'] = 'true';
213
- }
214
-
215
- $force_delete = array_get($_POST, 'smbd_special_force_delete');
216
- if ($force_delete == 'true') {
217
- $force_delete = true;
218
- } else {
219
- $force_delete = false;
220
- }
221
-
222
- // Drafts
223
- if ("drafs" == array_get($_POST, 'smbd_drafs')) {
224
- $options['post_status'] = 'draft';
225
- $drafts = $wp_query->query($options);
226
-
227
- foreach ($drafts as $draft) {
228
- wp_delete_post($draft->ID, $force_delete);
229
- }
230
- }
231
-
232
- // Revisions
233
- if ("revisions" == array_get($_POST, 'smbd_revisions')) {
234
- $revisions = $wpdb->get_results("select ID from $wpdb->posts where post_type = 'revision'");
235
-
236
- foreach ($revisions as $revision) {
237
- wp_delete_post($revision->ID, $force_delete);
238
- }
239
- }
240
-
241
- // Pending Posts
242
- if ("pending" == array_get($_POST, 'smbd_pending')) {
243
- $pendings = $wpdb->get_results("select ID from $wpdb->posts where post_status = 'pending'");
244
-
245
- foreach ($pendings as $pending) {
246
- wp_delete_post($pending->ID, $force_delete);
247
- }
248
- }
249
 
250
- // Future Posts
251
- if ("future" == array_get($_POST, 'smbd_future')) {
252
- $futures = $wpdb->get_results("select ID from $wpdb->posts where post_status = 'future'");
253
 
254
- foreach ($futures as $future) {
255
- wp_delete_post($future->ID, $force_delete);
256
- }
257
- }
258
 
259
- // Private Posts
260
- if ("private" == array_get($_POST, 'smbd_private')) {
261
- $privates = $wpdb->get_results("select ID from $wpdb->posts where post_status = 'private'");
 
 
 
 
262
 
263
- foreach ($privates as $private) {
264
- wp_delete_post($private->ID, $force_delete);
265
- }
266
- }
267
 
268
- // Pages
269
- if ("pages" == array_get($_POST, 'smbd_pages')) {
270
- $options['post_type'] = 'page';
271
- $pages = $wp_query->query($options);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
 
273
- foreach ($pages as $page) {
274
- wp_delete_post($page->ID, $force_delete);
275
- }
276
- }
277
-
278
- // Specific Pages
279
- if ("specificpages" == array_get($_POST, 'smdb_specific_pages')) {
280
- $urls = preg_split( '/\r\n|\r|\n/', array_get($_POST, 'smdb_specific_pages_urls') );
281
- foreach ($urls as $url) {
282
- $checkedurl = $url;
283
- if (substr($checkedurl ,0,1) == '/') {
284
- $checkedurl = get_site_url() . $checkedurl ;
285
- }
286
- $postid = url_to_postid( $checkedurl );
287
- wp_delete_post($postid, $force_delete);
288
- }
289
- }
290
-
291
- break;
292
- }
293
 
294
- // hook the admin notices action
295
- add_action( 'admin_notices', 'smbd_deleted_notice', 9 );
 
296
  }
 
297
  }
298
- }
299
 
300
- /**
301
- * Show deleted notice messages
302
- */
303
- if (!function_exists('smbd_deleted_notice')) {
304
- function smbd_deleted_notice() {
305
- echo "<div class = 'updated'><p>" . __("All the selected posts have been successfully deleted.", 'bulk-delete') . "</p></div>";
 
 
 
 
 
306
  }
307
- }
308
 
309
- /**
310
- * Show the Admin page
311
- */
312
- if (!function_exists('smbd_displayOptions')) {
313
- function smbd_displayOptions() {
314
  global $wpdb;
315
  ?>
316
  <div class="updated fade" style="background:#ff0;text-align:center;color: red;"><p><strong><?php _e("WARNING: Posts deleted once cannot be retrieved back. Use with caution.", 'bulk-delete'); ?></strong></p></div>
317
 
318
  <div class="wrap">
319
  <?php screen_icon(); ?>
320
- <h2>Bulk Delete</h2>
321
 
322
  <div id = "poststuff" style = "float:left; width:75%">
323
  <div class = "postbox">
@@ -339,7 +190,7 @@ if (!function_exists('smbd_displayOptions')) {
339
  $pending = $wpdb->get_var("select count(*) from $wpdb->posts where post_status = 'pending'");
340
  $future = $wpdb->get_var("select count(*) from $wpdb->posts where post_status = 'future'");
341
  $private = $wpdb->get_var("select count(*) from $wpdb->posts where post_status = 'private'");
342
- $pages = $wpdb->get_var("select count(*) from $wpdb->posts where post_type = 'page'");
343
  ?>
344
  <fieldset class="options">
345
  <table class="optiontable">
@@ -512,6 +363,31 @@ if (!function_exists('smbd_displayOptions')) {
512
  </td>
513
  </tr>
514
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
515
  </table>
516
  </fieldset>
517
  <p class="submit">
@@ -765,26 +641,340 @@ if (!function_exists('smbd_displayOptions')) {
765
  <?php
766
 
767
  // Display credits in Footer
768
- add_action( 'in_admin_footer', 'smbd_admin_footer' );
769
  }
770
- }
771
 
772
- /**
773
- * Check whether a key is present. If present returns the value, else returns the default value
774
- *
775
- * @param <array> $array - Array whose key has to be checked
776
- * @param <string> $key - key that has to be checked
777
- * @param <string> $default - the default value that has to be used, if the key is not found (optional)
778
- *
779
- * @return <mixed> If present returns the value, else returns the default value
780
- * @author Sudar
781
- */
782
- function array_get($array, $key, $default = NULL) {
783
- return isset($array[$key]) ? $array[$key] : $default;
784
- }
785
 
786
- /**
787
- * function to filter posts by days
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
788
  * @param <type> $where
789
  * @return <type>
790
  */
@@ -857,114 +1047,79 @@ if (!function_exists('smbd_get_tax_post')) {
857
  }
858
 
859
  /**
860
- * Add navigation menu
861
  */
862
- if(!function_exists('smbd_add_menu')) {
863
- function smbd_add_menu() {
864
- //Add a submenu to Manage
865
- $page = add_options_page("Bulk Delete", "Bulk Delete", 'manage_options', basename(__FILE__), "smbd_displayOptions");
866
- }
867
- }
868
 
869
- /**
870
- * Adds the settings link in the Plugin page. Based on http://striderweb.com/nerdaphernalia/2008/06/wp-use-action-links/
871
- * @staticvar <type> $this_plugin
872
- * @param <type> $links
873
- * @param <type> $file
874
- */
875
- if (!function_exists('smbd_filter_plugin_actions')) {
876
- function smbd_filter_plugin_actions($links, $file) {
877
- static $this_plugin;
878
- if( ! $this_plugin ) $this_plugin = plugin_basename(__FILE__);
879
 
880
- if( $file == $this_plugin ) {
881
- $settings_link = '<a href="options-general.php?page=bulk-delete.php">' . _('Manage') . '</a>';
882
- array_unshift( $links, $settings_link ); // before other links
883
- }
884
- return $links;
885
- }
886
- }
887
 
888
- /**
889
- * Adds Footer links. Based on http://striderweb.com/nerdaphernalia/2008/06/give-your-wordpress-plugin-credit/
890
- */
891
- if (!function_exists('smbd_admin_footer')) {
892
- function smbd_admin_footer() {
893
- $plugin_data = get_plugin_data( __FILE__ );
894
- printf('%1$s ' . __("plugin", 'bulk-delete') .' | ' . __("Version", 'bulk-delete') . ' %2$s | '. __('by', 'bulk-delete') . ' %3$s<br />', $plugin_data['Title'], $plugin_data['Version'], $plugin_data['Author']);
895
- ?>
896
- <script type="text/javascript">
897
 
898
- /**
899
- * Toggle closing of different sections
900
- *
901
- */
902
- jQuery(document).ready( function() {
903
- jQuery('.postbox h3').click( function() {
904
- jQuery(jQuery(this).parent().get(0)).toggleClass('closed');
905
- });
906
- });
907
 
908
- /**
909
- * Check All Checkboxes
910
- */
911
- function bd_checkAll(form) {
912
- for (i = 0, n = form.elements.length; i < n; i++) {
913
- if(form.elements[i].type == "checkbox" && !(form.elements[i].getAttribute('onclick',2))) {
914
- if(form.elements[i].checked == true)
915
- form.elements[i].checked = false;
916
- else
917
- form.elements[i].checked = true;
918
- }
919
  }
920
- }
921
 
922
- function toggle_date_restrict(el) {
923
- if (jQuery("#smbd_" + el + "_restrict").is(":checked")) {
924
- jQuery("#smbd_" + el + "_op").removeAttr('disabled');
925
- jQuery("#smbd_" + el + "_days").removeAttr('disabled');
926
  } else {
927
- jQuery("#smbd_" + el + "_op").attr('disabled', 'true');
928
- jQuery("#smbd_" + el + "_days").attr('disabled', 'true');
929
  }
930
- }
931
 
932
- function toggle_limit_restrict(el) {
933
- if (jQuery("#smbd_" + el + "_limit").is(":checked")) {
934
- jQuery("#smbd_" + el + "_limit_to").removeAttr('disabled');
935
- } else {
936
- jQuery("#smbd_" + el + "_limit_to").attr('disabled', 'true');
 
 
 
 
 
 
 
937
  }
938
  }
939
 
940
  /**
941
- * Validate Form
942
- */
943
- function bd_validateForm(form) {
944
- var valid = false;
945
- for (i = 0, n = form.elements.length; i < n; i++) {
946
- if(form.elements[i].type == "checkbox" && !(form.elements[i].getAttribute('onclick',2))) {
947
- if(form.elements[i].checked == true) {
948
- valid = true;
949
- break;
950
- }
 
 
 
 
 
 
 
951
  }
952
  }
953
 
954
- if (valid) {
955
- return confirm("<?php _e('Are you sure you want to delete all the selected posts', 'bulk-delete'); ?>");
956
- } else {
957
- alert ("<?php _e('Please select at least one', 'bulk-delete'); ?>");
958
- return false;
959
  }
960
- }
961
- </script>
962
 
963
- <?php
964
- }
 
965
  }
966
-
967
- add_filter( 'plugin_action_links', 'smbd_filter_plugin_actions', 10, 2 );
968
- add_action('admin_menu', 'smbd_add_menu');
969
- add_action('admin_init', 'smbd_request_handler');
970
  ?>
3
  Plugin Name: Bulk Delete
4
  Plugin Script: bulk-delete.php
5
  Plugin URI: http://sudarmuthu.com/wordpress/bulk-delete
6
+ Description: Bulk delete posts from selected categories, tags or custom taxonomies. Use it with caution.
7
  Donate Link: http://sudarmuthu.com/if-you-wanna-thank-me
8
+ Version: 3.0
9
  License: GPL
10
  Author: Sudar
11
  Author URI: http://sudarmuthu.com/
12
  Text Domain: bulk-delete
13
+ Domain Path: languages/
14
 
15
  === RELEASE NOTES ===
16
  2009-02-02 - v0.1 - first version
45
  - Added Serbian translations
46
  2012-12-20 - v2.2.2 - (Dev time: 0.5 hour)
47
  - Removed unused wpdb->prepare() function calls
48
+ 2013-04-27 - v3.0 - (Dev time: 10 hours)
49
+ - Added support for pro addons
50
+ - Added GUI to see cron jobs
51
  */
52
 
53
  /* Copyright 2009 Sudar Muthu (email : sudar@sudarmuthu.com)
67
  */
68
 
69
  /**
70
+ * Bulk Delete Main class
71
  */
72
+ class Bulk_Delete {
73
+
74
+ const VERSION = '3.0';
75
+ const JS_HANDLE = 'bulk-delete';
76
+ const JS_VARIABLE = 'BULK_DELETE';
77
+
78
+ /**
79
+ * Default constructor
80
+ */
81
+ public function __construct() {
82
  // Load localization domain
83
+ $this->translations = dirname(plugin_basename(__FILE__)) . '/languages/' ;
84
+ load_plugin_textdomain( 'bulk-delete', false, $this->translations);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
+ // Register hooks
87
+ add_action('admin_menu', array(&$this, 'add_menu'));
88
+ add_action('admin_init', array(&$this, 'request_handler'));
89
 
90
+ // Add more links in the plugin listing page
91
+ add_filter('plugin_action_links', array(&$this, 'filter_plugin_actions'), 10, 2 );
92
+ add_filter( 'plugin_row_meta', array( &$this, 'add_plugin_links' ), 10, 2 );
93
+ }
94
 
95
+ /**
96
+ * Add navigation menu
97
+ */
98
+ function add_menu() {
99
+ //Add a submenu to Manage
100
+ $this->admin_page = add_options_page(__("Bulk Delete", 'bulk-delete'), __("Bulk Delete", 'bulk-delete'), 'delete_posts', basename(__FILE__), array(&$this, 'display_setting_page'));
101
+ $this->cron_page = add_options_page(__("Bulk Delete Schedules", 'bulk-delete'), __("Bulk Delete Schedules", 'bulk-delete'), 'delete_posts', 'bulk-delete-cron', array(&$this, 'display_cron_page'));
102
 
103
+ add_action('admin_print_scripts-' . $this->admin_page, array(&$this, 'add_script'));
104
+ }
 
 
105
 
106
+ /**
107
+ * Enqueue JavaScript
108
+ */
109
+ function add_script() {
110
+ global $wp_scripts;
111
+
112
+ // uses code from http://trentrichardson.com/examples/timepicker/
113
+ wp_enqueue_script( 'jquery-ui-timepicker', plugins_url('/js/jquery-ui-timepicker.js', __FILE__), array('jquery-ui-slider', 'jquery-ui-datepicker'), '1.1.1', true);
114
+ wp_enqueue_script( self::JS_HANDLE, plugins_url('/js/bulk-delete.js', __FILE__), array('jquery-ui-timepicker'), self::VERSION, TRUE);
115
+
116
+ $ui = $wp_scripts->query('jquery-ui-core');
117
+
118
+ $url = "http://ajax.aspnetcdn.com/ajax/jquery.ui/{$ui->ver}/themes/smoothness/jquery-ui.css";
119
+ wp_enqueue_style('jquery-ui-smoothness', $url, false, $ui->ver);
120
+ wp_enqueue_style('jquery-ui-timepicker', plugins_url('/style/jquery-ui-timepicker.css', __FILE__), array(), '1.1.1');
121
+
122
+ // JavaScript messages
123
+ $msg = array(
124
+ 'deletewarning' => __('Are you sure you want to delete all the selected posts', 'bulk-delete'),
125
+ 'selectone' => __('Please select at least one', 'bulk-delete')
126
+ );
127
+ $translation_array = array( 'msg' => $msg );
128
+ wp_localize_script( self::JS_HANDLE, self::JS_VARIABLE, $translation_array );
129
+ }
130
 
131
+ /**
132
+ * Adds the settings link in the Plugin page. Based on http://striderweb.com/nerdaphernalia/2008/06/wp-use-action-links/
133
+ * @staticvar <type> $this_plugin
134
+ * @param <type> $links
135
+ * @param <type> $file
136
+ */
137
+ function filter_plugin_actions($links, $file) {
138
+ static $this_plugin;
139
+ if( ! $this_plugin ) $this_plugin = plugin_basename(__FILE__);
 
 
 
 
 
 
 
 
 
 
 
140
 
141
+ if( $file == $this_plugin ) {
142
+ $settings_link = '<a href="options-general.php?page=bulk-delete.php">' . __('Manage', 'bulk-delete') . '</a>';
143
+ array_unshift( $links, $settings_link ); // before other links
144
  }
145
+ return $links;
146
  }
 
147
 
148
+ /**
149
+ * Adds additional links in the Plugin listing. Based on http://zourbuth.com/archives/751/creating-additional-wordpress-plugin-links-row-meta/
150
+ */
151
+ function add_plugin_links($links, $file) {
152
+ $plugin = plugin_basename(__FILE__);
153
+
154
+ if ($file == $plugin) // only for this plugin
155
+ return array_merge( $links,
156
+ array( '<a href="http://sudarmuthu.com/out/bulk-delete-addons" target="_blank">' . __('Buy Addons', 'bulk-delete') . '</a>' )
157
+ );
158
+ return $links;
159
  }
 
160
 
161
+ /**
162
+ * Show the Admin page
163
+ */
164
+ function display_setting_page() {
 
165
  global $wpdb;
166
  ?>
167
  <div class="updated fade" style="background:#ff0;text-align:center;color: red;"><p><strong><?php _e("WARNING: Posts deleted once cannot be retrieved back. Use with caution.", 'bulk-delete'); ?></strong></p></div>
168
 
169
  <div class="wrap">
170
  <?php screen_icon(); ?>
171
+ <h2><?php _e('Bulk Delete', 'bulk-delete');?></h2>
172
 
173
  <div id = "poststuff" style = "float:left; width:75%">
174
  <div class = "postbox">
190
  $pending = $wpdb->get_var("select count(*) from $wpdb->posts where post_status = 'pending'");
191
  $future = $wpdb->get_var("select count(*) from $wpdb->posts where post_status = 'future'");
192
  $private = $wpdb->get_var("select count(*) from $wpdb->posts where post_status = 'private'");
193
+ $pages = $wpdb->get_var("select count(*) from $wpdb->posts where post_type = 'page' AND post_status = 'publish' ");
194
  ?>
195
  <fieldset class="options">
196
  <table class="optiontable">
363
  </td>
364
  </tr>
365
 
366
+ <tr>
367
+ <td scope="row" colspan="2">
368
+ <input name="smbd_cats_cron" value = "false" type = "radio" checked="checked" /> <?php _e('Delete now', 'bulk-delete'); ?>
369
+ <input name="smbd_cats_cron" value = "true" type = "radio" id = "smbd_cats_cron" disabled > <?php _e('Schedule', 'bulk-delete'); ?>
370
+ <input name="smbd_cats_cron_start" id = "smbd_cats_cron_start" value = "now" type = "text" disabled><?php _e('repeat ', 'bulk-delete');?>
371
+ <select name = "smbd_cats_cron_freq" id = "smbd_cats_cron_freq" disabled>
372
+ <option value = "-1"><?php _e("Don't repeat", 'bulk-delete'); ?></option>
373
+ <?php
374
+ $schedules = wp_get_schedules();
375
+ foreach($schedules as $key => $value) {
376
+ ?>
377
+ <option value = "<?php echo $key; ?>"><?php echo $value['display']; ?></option>
378
+ <?php
379
+ }
380
+ ?>
381
+ </select>
382
+ <span class = "bd-cats-pro" style = "color:red"><?php _e('Only available in Pro Addon', 'bulk-delete'); ?> <a href = "http://sudarmuthu.com/out/bulk-delete-category-addon">Buy now</a></span>
383
+ </td>
384
+ </tr>
385
+ <tr>
386
+ <td scope="row" colspan="2">
387
+ <?php _e("Enter time in Y-m-d H:i:s format or enter now to use current time", 'bulk-delete');?>
388
+ </td>
389
+ </tr>
390
+
391
  </table>
392
  </fieldset>
393
  <p class="submit">
641
  <?php
642
 
643
  // Display credits in Footer
644
+ add_action( 'in_admin_footer', array(&$this, 'admin_footer' ));
645
  }
 
646
 
647
+ /**
648
+ * Adds Footer links. Based on http://striderweb.com/nerdaphernalia/2008/06/give-your-wordpress-plugin-credit/
649
+ */
650
+ function admin_footer() {
651
+ $plugin_data = get_plugin_data( __FILE__ );
652
+ printf('%1$s ' . __("plugin", 'bulk-delete') .' | ' . __("Version", 'bulk-delete') . ' %2$s | '. __('by', 'bulk-delete') . ' %3$s<br />', $plugin_data['Title'], $plugin_data['Version'], $plugin_data['Author']);
653
+ }
 
 
 
 
 
 
654
 
655
+ /**
656
+ * Display the schedule page
657
+ */
658
+ function display_cron_page() {
659
+
660
+ if(!class_exists('WP_List_Table')){
661
+ require_once( ABSPATH . WPINC . '/class-wp-list-table.php' );
662
+ }
663
+ if (!class_exists('Cron_List_Table')) {
664
+ require_once dirname(__FILE__) . '/include/class-cron-list-table.php';
665
+ }
666
+
667
+ //Prepare Table of elements
668
+ $cron_list_table = new Cron_List_Table();
669
+ $cron_list_table->prepare_items($this->get_cron_schedules());
670
+
671
+ ?>
672
+ <div class="wrap">
673
+ <?php screen_icon(); ?>
674
+ <h2><?php _e('Bulk Delete Schedules', 'bulk-delete');?></h2>
675
+ <?php
676
+ //Table of elements
677
+ $cron_list_table->display();
678
+ ?>
679
+ </div>
680
+ <?php
681
+ }
682
+
683
+ /**
684
+ * Request Handler
685
+ */
686
+ function request_handler() {
687
+ global $wpdb;
688
+
689
+ if (isset($_GET['smbd_action'])) {
690
+
691
+ switch($_GET['smbd_action']) {
692
+
693
+ case 'delete-cron':
694
+ //TODO: Check for nonce and referer
695
+ $cron_id = absint($_GET['cron_id']);
696
+ $cron_items = $this->get_cron_schedules();
697
+ wp_unschedule_event($cron_items[$cron_id]['timestamp'], $cron_items[$cron_id]['type'], $cron_items[$cron_id]['args']);
698
+
699
+ break;
700
+ }
701
+ }
702
+
703
+ if (isset($_POST['smbd_action'])) {
704
+
705
+ $wp_query = new WP_Query;
706
+ check_admin_referer( 'bulk-delete-posts');
707
+
708
+ switch($_POST['smbd_action']) {
709
+
710
+ case "bulk-delete-cats":
711
+ // delete by cats
712
+
713
+ $delete_options = array();
714
+ $delete_options['selected_cats'] = array_get($_POST, 'smbd_cats');
715
+ $delete_options['restrict'] = array_get($_POST, 'smbd_cats_restrict', FALSE);
716
+ $delete_options['private'] = array_get($_POST, 'smbd_cats_private');
717
+ $delete_options['limit_to'] = absint(array_get($_POST, 'smbd_cats_limits_to', 0));
718
+ $delete_options['force_delete'] = array_get($_POST, 'smbd_cats_force_delete', 'false');
719
+
720
+ $delete_options['cats_op'] = array_get($_POST, 'smbd_cats_op');
721
+ $delete_options['cats_days'] = array_get($_POST, 'smbd_cats_days');
722
+
723
+ if (array_get($_POST, 'smbd_cats_cron', 'false') == 'true') {
724
+ $freq = $_POST['smbd_cats_cron_freq'];
725
+ $time = strtotime($_POST['smbd_cats_cron_start']) - get_option('gmt_offset');
726
+
727
+ if ($freq == -1) {
728
+ wp_schedule_single_event($time, 'do-bulk-delete-cats', array($delete_options));
729
+ } else {
730
+ wp_schedule_event($time, $freq , 'do-bulk-delete-cats', array($delete_options));
731
+ }
732
+ } else {
733
+ smbd_delete_cats($delete_options);
734
+ }
735
+
736
+ break;
737
+
738
+ case "bulk-delete-tags":
739
+ // delete by tags
740
+ $selected_tags = array_get($_POST, 'smbd_tags');
741
+ if (array_get($_POST, 'smbd_tags_restrict', 'false') == "true") {
742
+ add_filter ('posts_where', 'smbd_tags_by_days');
743
+ }
744
+
745
+ $private = array_get($_POST, 'smbd_tags_private', 'false');
746
+
747
+ if ($private == 'true') {
748
+ $options = array('tag__in'=>$selected_tags,'post_status'=>'private', 'post_type'=>'post');
749
+ } else {
750
+ $options = array('tag__in'=>$selected_tags,'post_status'=>'publish', 'post_type'=>'post');
751
+ }
752
+
753
+ $limit_to = absint(array_get($_POST, 'smbd_tags_limits_to', 0));
754
+
755
+ if ($limit_to > 0) {
756
+ $options['showposts'] = $limit_to;
757
+ } else {
758
+ $options['nopaging'] = 'true';
759
+ }
760
+
761
+ $force_delete = array_get($_POST, 'smbd_tags_force_delete');
762
+
763
+ if ($force_delete == 'true') {
764
+ $force_delete = true;
765
+ } else {
766
+ $force_delete = false;
767
+ }
768
+
769
+ $posts = $wp_query->query($options);
770
+
771
+ foreach ($posts as $post) {
772
+ wp_delete_post($post->ID, $force_delete);
773
+ }
774
+
775
+ break;
776
+
777
+ case "bulk-delete-taxs":
778
+ // delete by taxs
779
+ $selected_taxs = array_get($_POST, 'smbd_taxs');
780
+
781
+ foreach ($selected_taxs as $selected_tax) {
782
+ $postids = smbd_get_tax_post($selected_tax);
783
+
784
+ if (array_get($_POST, 'smbd_taxs_restrict', 'false') == "true") {
785
+ add_filter ('posts_where', 'smbd_taxs_by_days');
786
+ }
787
+
788
+ $private = array_get($_POST, 'smbd_taxs_private');
789
+
790
+ if ($private == 'true') {
791
+ $options = array('post__in'=>$postids,'post_status'=>'private', 'post_type'=>'post');
792
+ } else {
793
+ $options = array('post__in'=>$postids,'post_status'=>'publish', 'post_type'=>'post');
794
+ }
795
+
796
+ $limit_to = absint(array_get($_POST, 'smbd_taxs_limits_to', 0));
797
+
798
+ if ($limit_to > 0) {
799
+ $options['showposts'] = $limit_to;
800
+ } else {
801
+ $options['nopaging'] = 'true';
802
+ }
803
+
804
+ $force_delete = array_get($_POST, 'smbd_taxs_force_delete');
805
+
806
+ if ($force_delete == 'true') {
807
+ $force_delete = true;
808
+ } else {
809
+ $force_delete = false;
810
+ }
811
+
812
+ $posts = $wp_query->query($options);
813
+ foreach ($posts as $post) {
814
+ wp_delete_post($post->ID, $force_delete);
815
+ }
816
+ }
817
+
818
+ break;
819
+
820
+ case "bulk-delete-special":
821
+ $options = array();
822
+
823
+ $limit_to = absint(array_get($_POST, 'smbd_special_limit_to', 0));
824
+
825
+ if ($limit_to > 0) {
826
+ $options['showposts'] = $limit_to;
827
+ } else {
828
+ $options['nopaging'] = 'true';
829
+ }
830
+
831
+ $force_delete = array_get($_POST, 'smbd_special_force_delete');
832
+ if ($force_delete == 'true') {
833
+ $force_delete = true;
834
+ } else {
835
+ $force_delete = false;
836
+ }
837
+
838
+ // Drafts
839
+ if ("drafs" == array_get($_POST, 'smbd_drafs')) {
840
+ $options['post_status'] = 'draft';
841
+ $drafts = $wp_query->query($options);
842
+
843
+ foreach ($drafts as $draft) {
844
+ wp_delete_post($draft->ID, $force_delete);
845
+ }
846
+ }
847
+
848
+ // Revisions
849
+ if ("revisions" == array_get($_POST, 'smbd_revisions')) {
850
+ $revisions = $wpdb->get_results("select ID from $wpdb->posts where post_type = 'revision'");
851
+
852
+ foreach ($revisions as $revision) {
853
+ wp_delete_post($revision->ID, $force_delete);
854
+ }
855
+ }
856
+
857
+ // Pending Posts
858
+ if ("pending" == array_get($_POST, 'smbd_pending')) {
859
+ $pendings = $wpdb->get_results("select ID from $wpdb->posts where post_status = 'pending'");
860
+
861
+ foreach ($pendings as $pending) {
862
+ wp_delete_post($pending->ID, $force_delete);
863
+ }
864
+ }
865
+
866
+ // Future Posts
867
+ if ("future" == array_get($_POST, 'smbd_future')) {
868
+ $futures = $wpdb->get_results("select ID from $wpdb->posts where post_status = 'future'");
869
+
870
+ foreach ($futures as $future) {
871
+ wp_delete_post($future->ID, $force_delete);
872
+ }
873
+ }
874
+
875
+ // Private Posts
876
+ if ("private" == array_get($_POST, 'smbd_private')) {
877
+ $privates = $wpdb->get_results("select ID from $wpdb->posts where post_status = 'private'");
878
+
879
+ foreach ($privates as $private) {
880
+ wp_delete_post($private->ID, $force_delete);
881
+ }
882
+ }
883
+
884
+ // Pages
885
+ if ("pages" == array_get($_POST, 'smbd_pages')) {
886
+ $options['post_type'] = 'page';
887
+ $pages = $wp_query->query($options);
888
+
889
+ foreach ($pages as $page) {
890
+ wp_delete_post($page->ID, $force_delete);
891
+ }
892
+ }
893
+
894
+ // Specific Pages
895
+ if ("specificpages" == array_get($_POST, 'smdb_specific_pages')) {
896
+ $urls = preg_split( '/\r\n|\r|\n/', array_get($_POST, 'smdb_specific_pages_urls') );
897
+ foreach ($urls as $url) {
898
+ $checkedurl = $url;
899
+ if (substr($checkedurl ,0,1) == '/') {
900
+ $checkedurl = get_site_url() . $checkedurl ;
901
+ }
902
+ $postid = url_to_postid( $checkedurl );
903
+ wp_delete_post($postid, $force_delete);
904
+ }
905
+ }
906
+
907
+ break;
908
+ }
909
+
910
+ // hook the admin notices action
911
+ add_action( 'admin_notices', array(&$this, 'deleted_notice'), 9 );
912
+ }
913
+ }
914
+
915
+ /**
916
+ * Show deleted notice messages
917
+ */
918
+ function deleted_notice() {
919
+ echo "<div class = 'updated'><p>" . __("All the selected posts have been successfully deleted.", 'bulk-delete') . "</p></div>";
920
+ }
921
+
922
+ /**
923
+ * Get the list of cron schedules
924
+ *
925
+ * @return array - The list of cron schedules
926
+ */
927
+ private function get_cron_schedules() {
928
+
929
+ $cron_items = array();
930
+ $cron = _get_cron_array();
931
+ $date_format = _x( 'M j, Y @ G:i', 'Cron table date format', 'bulk-delete' );
932
+ $i = 0;
933
+
934
+ foreach ( $cron as $timestamp => $cronhooks ) {
935
+ foreach ( (array) $cronhooks as $hook => $events ) {
936
+ if (substr($hook, 0, 15) == 'do-bulk-delete-') {
937
+ $cron_item = array();
938
+
939
+ foreach ( (array) $events as $key => $event ) {
940
+ $cron_item['timestamp'] = $timestamp;
941
+ $cron_item['due'] = date_i18n( $date_format, $timestamp );
942
+ $cron_item['schedule'] = $event['schedule'];
943
+ $cron_item['type'] = $hook;
944
+ $cron_item['args'] = $event['args'];
945
+ $cron_item['id'] = $i;
946
+ }
947
+
948
+ $cron_items[$i] = $cron_item;
949
+ $i++;
950
+ }
951
+ }
952
+ }
953
+ return $cron_items;
954
+ }
955
+ }
956
+
957
+ // Start this plugin once all other plugins are fully loaded
958
+ add_action( 'init', 'Bulk_Delete' ); function Bulk_Delete() { global $Bulk_Delete; $Bulk_Delete = new Bulk_Delete(); }
959
+
960
+ /**
961
+ * Check whether a key is present. If present returns the value, else returns the default value
962
+ *
963
+ * @param <array> $array - Array whose key has to be checked
964
+ * @param <string> $key - key that has to be checked
965
+ * @param <string> $default - the default value that has to be used, if the key is not found (optional)
966
+ *
967
+ * @return <mixed> If present returns the value, else returns the default value
968
+ * @author Sudar
969
+ */
970
+ if (!function_exists('array_get')) {
971
+ function array_get($array, $key, $default = NULL) {
972
+ return isset($array[$key]) ? $array[$key] : $default;
973
+ }
974
+ }
975
+
976
+ /**
977
+ * function to filter posts by days
978
  * @param <type> $where
979
  * @return <type>
980
  */
1047
  }
1048
 
1049
  /**
1050
+ * Delete posts by category
1051
  */
1052
+ function smbd_delete_cats($delete_options) {
 
 
 
 
 
1053
 
1054
+ $selected_cats = $delete_options['selected_cats'];
 
 
 
 
 
 
 
 
 
1055
 
1056
+ $private = $delete_options['private'];
 
 
 
 
 
 
1057
 
1058
+ if ($private == 'true') {
1059
+ $options = array('category__in'=>$selected_cats,'post_status'=>'private', 'post_type'=>'post');
1060
+ } else {
1061
+ $options = array('category__in'=>$selected_cats,'post_status'=>'publish', 'post_type'=>'post');
1062
+ }
 
 
 
 
1063
 
1064
+ $limit_to = $delete_options['limit_to'];
 
 
 
 
 
 
 
 
1065
 
1066
+ if ($limit_to > 0) {
1067
+ $options['showposts'] = $limit_to;
1068
+ } else {
1069
+ $options['nopaging'] = 'true';
 
 
 
 
 
 
 
1070
  }
 
1071
 
1072
+ $force_delete = $delete_options['force_delete'];
1073
+
1074
+ if ($force_delete == 'true') {
1075
+ $force_delete = true;
1076
  } else {
1077
+ $force_delete = false;
 
1078
  }
 
1079
 
1080
+ if ($delete_options['restrict'] == "true") {
1081
+ $options['cats_op'] = $delete_options['cats_op'];
1082
+ $options['cats_days'] = $delete_options['cats_days'];
1083
+
1084
+ $bulkDeleteCatDays = new BulkDeleteCatDays;
1085
+ }
1086
+
1087
+ $wp_query = new WP_Query();
1088
+ $posts = $wp_query->query($options);
1089
+
1090
+ foreach ($posts as $post) {
1091
+ wp_delete_post($post->ID, $force_delete);
1092
  }
1093
  }
1094
 
1095
  /**
1096
+ * Class that encapsulates the deletion of Categories
1097
+ */
1098
+ class BulkDeleteCatDays {
1099
+ var $days;
1100
+ var $op;
1101
+
1102
+ public function __construct(){
1103
+ add_action( 'parse_query', array( $this, 'parse_query' ) );
1104
+ }
1105
+
1106
+ public function parse_query( $query ) {
1107
+ if( isset( $query->query_vars['cats_days'] ) ){
1108
+ $this->days = $query->query_vars['cats_days'];
1109
+ $this->op = $query->query_vars['cats_op'];
1110
+
1111
+ add_filter( 'posts_where', array( $this, 'filter_where' ) );
1112
+ add_filter( 'posts_selection', array( $this, 'remove_where' ) );
1113
  }
1114
  }
1115
 
1116
+ public function filter_where($where = '') {
1117
+ $where .= " AND post_date " . $this->op . " '" . date('y-m-d', strtotime('-' . $this->days . ' days')) . "'";
1118
+ return $where;
 
 
1119
  }
 
 
1120
 
1121
+ public function remove_where() {
1122
+ remove_filter( 'posts_where', array( $this, 'filter_where' ) );
1123
+ }
1124
  }
 
 
 
 
1125
  ?>
include/class-cron-list-table.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Table to show cron list
4
+ *
5
+ * @package WordPress
6
+ * @subpackage bulk-delete
7
+ * @author Sudar
8
+ */
9
+ class Cron_List_Table extends WP_List_Table {
10
+
11
+ /**
12
+ * Constructor, we override the parent to pass our own arguments
13
+ * We usually focus on three parameters: singular and plural labels, as well as whether the class supports AJAX.
14
+ */
15
+ function __construct() {
16
+ parent::__construct( array(
17
+ 'singular'=> 'cron_list', //Singular label
18
+ 'plural' => 'cron_lists', //plural label, also this well be one of the table css class
19
+ 'ajax' => false //We won't support Ajax for this table
20
+ ) );
21
+ }
22
+
23
+ /**
24
+ * Add extra markup in the toolbars before or after the list
25
+ * @param string $which, helps you decide if you add the markup after (bottom) or before (top) the list
26
+ */
27
+ function extra_tablenav( $which ) {
28
+ if ( $which == "top" ){
29
+ //The code that goes before the table is here
30
+ echo '<p>';
31
+ _e('This is the list of jobs that are currently scheduled for auto deleting posts in Bulk Delete Plugin.', 'bulk-delete');
32
+ echo '</p>';
33
+ }
34
+ if ( $which == "bottom" ){
35
+ //The code that goes after the table is there
36
+ echo '<p>&nbsp;';
37
+ echo '</p>';
38
+ echo '<p>';
39
+ echo '<strong>';
40
+ _e('Note: ', 'bulk-delete');
41
+ echo '</strong>';
42
+ _e('Scheduling auto post deletion is available only when you buy pro addons.', 'bulk-delete');
43
+ echo '</p>';
44
+ echo '<p>';
45
+ _e('The following are the list of pro addons that are currently available.', 'bulk-delete');
46
+ echo '</p>';
47
+ echo '<h3>'; _e('Bulk Delete Schedule Categories'); echo '</h3>';
48
+ echo '<p>';
49
+ _e('This addon adds the ability to schedule auto delete of categories. The cost of this addon is $15. You can buy it through paypal by clicking the below button.', 'bulk-delete');
50
+ echo '</p>';
51
+ ?>
52
+
53
+ <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
54
+ <input type="hidden" name="cmd" value="_s-xclick">
55
+ <input type="hidden" name="hosted_button_id" value="RTJ77HKUS9C9L">
56
+ <input type="image" src="https://www.paypalobjects.com/en_GB/i/btn/btn_buynowCC_LG.gif" border="0" name="submit" alt="PayPal – The safer, easier way to pay online.">
57
+ <img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1">
58
+ </form>
59
+ <?php
60
+ echo '<p>';
61
+ _e('More addons coming soon', 'bulk-delete');
62
+ echo '</p>';
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Define the columns that are going to be used in the table
68
+ * @return array $columns, the array of columns to use with the table
69
+ */
70
+ function get_columns() {
71
+ return $columns= array(
72
+ 'col_cron_due'=>__('Next Due (GMT/UTC)'),
73
+ 'col_cron_schedule'=>__('Schedule'),
74
+ 'col_cron_type'=>__('Type'),
75
+ 'col_cron_options'=>__('Options')
76
+ );
77
+ }
78
+
79
+ /**
80
+ * Decide which columns to activate the sorting functionality on
81
+ * @return array $sortable, the array of columns that can be sorted by the user
82
+ */
83
+ public function get_sortable_columns() {
84
+ return $sortable = array(
85
+ 'col_cron_type'=>array('cron_type')
86
+ );
87
+ }
88
+
89
+ /**
90
+ * Prepare the table with different parameters, pagination, columns and table elements
91
+ */
92
+ function prepare_items($cron_items) {
93
+ $totalitems = count($cron_items);
94
+
95
+ //How many to display per page?
96
+ $perpage = 50;
97
+
98
+ //How many pages do we have in total?
99
+ $totalpages = ceil($totalitems/$perpage);
100
+
101
+ /* -- Register the pagination -- */
102
+ $this->set_pagination_args( array(
103
+ "total_items" => $totalitems,
104
+ "total_pages" => $totalpages,
105
+ "per_page" => $perpage,
106
+ ) );
107
+ //The pagination links are automatically built according to those parameters
108
+
109
+ /* — Register the Columns — */
110
+ $columns = $this->get_columns();
111
+ $hidden = array();
112
+ $sortable = $this->get_sortable_columns();
113
+ $this->_column_headers = array($columns, $hidden, $sortable);
114
+
115
+ $this->items = $cron_items;
116
+ }
117
+
118
+ function column_col_cron_due($item) {
119
+ //Build row actions
120
+ $actions = array(
121
+ 'delete' => sprintf('<a href="?page=%s&smbd_action=%s&cron_id=%s">%s</a>',$_REQUEST['page'], 'delete-cron', $item['id'], __('Delete', 'bulk-delete')),
122
+ );
123
+
124
+ //Return the title contents
125
+ return sprintf('%1$s <span style="color:silver">(%2$s)</span>%3$s',
126
+ /*$1%s*/ $item['due'],
127
+ /*$2%s*/ $item['timestamp'],
128
+ /*$3%s*/ $this->row_actions($actions)
129
+ );
130
+ }
131
+
132
+ function column_col_cron_schedule($item) {
133
+ echo $item['schedule'];
134
+ }
135
+
136
+ function column_col_cron_type($item) {
137
+ echo $item['type'];
138
+ }
139
+
140
+ function column_col_cron_options($item) {
141
+ // TODO: Make it pretty
142
+ print_r ($item['args']);
143
+ }
144
+
145
+ function no_items() {
146
+ _e('You have not scheduled any bulk delete jobs.', 'bulk-delete');
147
+ }
148
+ }
149
+ ?>
js/bulk-delete.js ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * JavaScript for Bulk Delete Plugin
3
+ *
4
+ * http://sudarmuthu.com/wordpress/bulk-delete
5
+ *
6
+ * @author: Sudar <http://sudarmuthu.com>
7
+ *
8
+ */
9
+
10
+ /*global BULK_DELETE, jQuery, document*/
11
+ jQuery(document).ready(function () {
12
+ /**
13
+ * Toggle closing of different sections
14
+ */
15
+ jQuery('.postbox h3').click(function () {
16
+ jQuery(jQuery(this).parent().get(0)).toggleClass('closed');
17
+ });
18
+
19
+ // invoke the date time picker
20
+ jQuery('#smbd_cats_cron_start').datetimepicker({
21
+ timeFormat: 'HH-mm-ss'
22
+ });
23
+ });
24
+
25
+ /**
26
+ * Check All Checkboxes
27
+ */
28
+ function bd_checkAll(form) {
29
+ for (i = 0, n = form.elements.length; i < n; i++) {
30
+ if (form.elements[i].type == "checkbox" && !(form.elements[i].getAttribute('onclick', 2))) {
31
+ if (form.elements[i].checked == true) {
32
+ form.elements[i].checked = false;
33
+ } else {
34
+ form.elements[i].checked = true;
35
+ }
36
+ }
37
+ }
38
+ }
39
+
40
+ function toggle_date_restrict(el) {
41
+ if (jQuery("#smbd_" + el + "_restrict").is(":checked")) {
42
+ jQuery("#smbd_" + el + "_op").removeAttr('disabled');
43
+ jQuery("#smbd_" + el + "_days").removeAttr('disabled');
44
+ } else {
45
+ jQuery("#smbd_" + el + "_op").attr('disabled', 'true');
46
+ jQuery("#smbd_" + el + "_days").attr('disabled', 'true');
47
+ }
48
+ }
49
+
50
+ function toggle_limit_restrict(el) {
51
+ if (jQuery("#smbd_" + el + "_limit").is(":checked")) {
52
+ jQuery("#smbd_" + el + "_limit_to").removeAttr('disabled');
53
+ } else {
54
+ jQuery("#smbd_" + el + "_limit_to").attr('disabled', 'true');
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Validate Form
60
+ */
61
+ function bd_validateForm(form) {
62
+ var valid = false;
63
+ for (i = 0, n = form.elements.length; i < n; i++) {
64
+ if (form.elements[i].type == "checkbox" && !(form.elements[i].getAttribute('onclick', 2))) {
65
+ if (form.elements[i].checked == true) {
66
+ valid = true;
67
+ break;
68
+ }
69
+ }
70
+ }
71
+
72
+ if (valid) {
73
+ return confirm(BULK_DELETE.msg.deletewarning);
74
+ } else {
75
+ alert(BULK_DELETE.msg.selectone);
76
+ return false;
77
+ }
78
+ }
js/jquery-ui-timepicker.js ADDED
@@ -0,0 +1,1882 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * jQuery timepicker addon
3
+ * By: Trent Richardson [http://trentrichardson.com]
4
+ * Version 1.1.1
5
+ * Last Modified: 11/07/2012
6
+ *
7
+ * Copyright 2012 Trent Richardson
8
+ * You may use this project under MIT or GPL licenses.
9
+ * http://trentrichardson.com/Impromptu/GPL-LICENSE.txt
10
+ * http://trentrichardson.com/Impromptu/MIT-LICENSE.txt
11
+ */
12
+
13
+ /*jslint evil: true, white: false, undef: false, nomen: false */
14
+
15
+ (function($) {
16
+
17
+ /*
18
+ * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
19
+ */
20
+ $.ui.timepicker = $.ui.timepicker || {};
21
+ if ($.ui.timepicker.version) {
22
+ return;
23
+ }
24
+
25
+ /*
26
+ * Extend jQueryUI, get it started with our version number
27
+ */
28
+ $.extend($.ui, {
29
+ timepicker: {
30
+ version: "1.1.1"
31
+ }
32
+ });
33
+
34
+ /*
35
+ * Timepicker manager.
36
+ * Use the singleton instance of this class, $.timepicker, to interact with the time picker.
37
+ * Settings for (groups of) time pickers are maintained in an instance object,
38
+ * allowing multiple different settings on the same page.
39
+ */
40
+ function Timepicker() {
41
+ this.regional = []; // Available regional settings, indexed by language code
42
+ this.regional[''] = { // Default regional settings
43
+ currentText: 'Now',
44
+ closeText: 'Done',
45
+ amNames: ['AM', 'A'],
46
+ pmNames: ['PM', 'P'],
47
+ timeFormat: 'HH:mm',
48
+ timeSuffix: '',
49
+ timeOnlyTitle: 'Choose Time',
50
+ timeText: 'Time',
51
+ hourText: 'Hour',
52
+ minuteText: 'Minute',
53
+ secondText: 'Second',
54
+ millisecText: 'Millisecond',
55
+ timezoneText: 'Time Zone',
56
+ isRTL: false
57
+ };
58
+ this._defaults = { // Global defaults for all the datetime picker instances
59
+ showButtonPanel: true,
60
+ timeOnly: false,
61
+ showHour: true,
62
+ showMinute: true,
63
+ showSecond: false,
64
+ showMillisec: false,
65
+ showTimezone: false,
66
+ showTime: true,
67
+ stepHour: 1,
68
+ stepMinute: 1,
69
+ stepSecond: 1,
70
+ stepMillisec: 1,
71
+ hour: 0,
72
+ minute: 0,
73
+ second: 0,
74
+ millisec: 0,
75
+ timezone: null,
76
+ useLocalTimezone: false,
77
+ defaultTimezone: "+0000",
78
+ hourMin: 0,
79
+ minuteMin: 0,
80
+ secondMin: 0,
81
+ millisecMin: 0,
82
+ hourMax: 23,
83
+ minuteMax: 59,
84
+ secondMax: 59,
85
+ millisecMax: 999,
86
+ minDateTime: null,
87
+ maxDateTime: null,
88
+ onSelect: null,
89
+ hourGrid: 0,
90
+ minuteGrid: 0,
91
+ secondGrid: 0,
92
+ millisecGrid: 0,
93
+ alwaysSetTime: true,
94
+ separator: ' ',
95
+ altFieldTimeOnly: true,
96
+ altTimeFormat: null,
97
+ altSeparator: null,
98
+ altTimeSuffix: null,
99
+ pickerTimeFormat: null,
100
+ pickerTimeSuffix: null,
101
+ showTimepicker: true,
102
+ timezoneIso8601: false,
103
+ timezoneList: null,
104
+ addSliderAccess: false,
105
+ sliderAccessArgs: null,
106
+ controlType: 'slider',
107
+ defaultValue: null,
108
+ parse: 'strict'
109
+ };
110
+ $.extend(this._defaults, this.regional['']);
111
+ }
112
+
113
+ $.extend(Timepicker.prototype, {
114
+ $input: null,
115
+ $altInput: null,
116
+ $timeObj: null,
117
+ inst: null,
118
+ hour_slider: null,
119
+ minute_slider: null,
120
+ second_slider: null,
121
+ millisec_slider: null,
122
+ timezone_select: null,
123
+ hour: 0,
124
+ minute: 0,
125
+ second: 0,
126
+ millisec: 0,
127
+ timezone: null,
128
+ defaultTimezone: "+0000",
129
+ hourMinOriginal: null,
130
+ minuteMinOriginal: null,
131
+ secondMinOriginal: null,
132
+ millisecMinOriginal: null,
133
+ hourMaxOriginal: null,
134
+ minuteMaxOriginal: null,
135
+ secondMaxOriginal: null,
136
+ millisecMaxOriginal: null,
137
+ ampm: '',
138
+ formattedDate: '',
139
+ formattedTime: '',
140
+ formattedDateTime: '',
141
+ timezoneList: null,
142
+ units: ['hour','minute','second','millisec'],
143
+ control: null,
144
+
145
+ /*
146
+ * Override the default settings for all instances of the time picker.
147
+ * @param settings object - the new settings to use as defaults (anonymous object)
148
+ * @return the manager object
149
+ */
150
+ setDefaults: function(settings) {
151
+ extendRemove(this._defaults, settings || {});
152
+ return this;
153
+ },
154
+
155
+ /*
156
+ * Create a new Timepicker instance
157
+ */
158
+ _newInst: function($input, o) {
159
+ var tp_inst = new Timepicker(),
160
+ inlineSettings = {},
161
+ fns = {},
162
+ overrides, i;
163
+
164
+ for (var attrName in this._defaults) {
165
+ if(this._defaults.hasOwnProperty(attrName)){
166
+ var attrValue = $input.attr('time:' + attrName);
167
+ if (attrValue) {
168
+ try {
169
+ inlineSettings[attrName] = eval(attrValue);
170
+ } catch (err) {
171
+ inlineSettings[attrName] = attrValue;
172
+ }
173
+ }
174
+ }
175
+ }
176
+ overrides = {
177
+ beforeShow: function (input, dp_inst) {
178
+ if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) {
179
+ return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);
180
+ }
181
+ },
182
+ onChangeMonthYear: function (year, month, dp_inst) {
183
+ // Update the time as well : this prevents the time from disappearing from the $input field.
184
+ tp_inst._updateDateTime(dp_inst);
185
+ if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) {
186
+ tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
187
+ }
188
+ },
189
+ onClose: function (dateText, dp_inst) {
190
+ if (tp_inst.timeDefined === true && $input.val() !== '') {
191
+ tp_inst._updateDateTime(dp_inst);
192
+ }
193
+ if ($.isFunction(tp_inst._defaults.evnts.onClose)) {
194
+ tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);
195
+ }
196
+ }
197
+ };
198
+ for (i in overrides) {
199
+ if (overrides.hasOwnProperty(i)) {
200
+ fns[i] = o[i] || null;
201
+ }
202
+ }
203
+ tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, overrides, {
204
+ evnts:fns,
205
+ timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
206
+ });
207
+ tp_inst.amNames = $.map(tp_inst._defaults.amNames, function(val) {
208
+ return val.toUpperCase();
209
+ });
210
+ tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function(val) {
211
+ return val.toUpperCase();
212
+ });
213
+
214
+ // controlType is string - key to our this._controls
215
+ if(typeof(tp_inst._defaults.controlType) === 'string'){
216
+ if($.fn[tp_inst._defaults.controlType] === undefined){
217
+ tp_inst._defaults.controlType = 'select';
218
+ }
219
+ tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];
220
+ }
221
+ // controlType is an object and must implement create, options, value methods
222
+ else{
223
+ tp_inst.control = tp_inst._defaults.controlType;
224
+ }
225
+
226
+ if (tp_inst._defaults.timezoneList === null) {
227
+ var timezoneList = ['-1200', '-1100', '-1000', '-0930', '-0900', '-0800', '-0700', '-0600', '-0500', '-0430', '-0400', '-0330', '-0300', '-0200', '-0100', '+0000',
228
+ '+0100', '+0200', '+0300', '+0330', '+0400', '+0430', '+0500', '+0530', '+0545', '+0600', '+0630', '+0700', '+0800', '+0845', '+0900', '+0930',
229
+ '+1000', '+1030', '+1100', '+1130', '+1200', '+1245', '+1300', '+1400'];
230
+
231
+ if (tp_inst._defaults.timezoneIso8601) {
232
+ timezoneList = $.map(timezoneList, function(val) {
233
+ return val == '+0000' ? 'Z' : (val.substring(0, 3) + ':' + val.substring(3));
234
+ });
235
+ }
236
+ tp_inst._defaults.timezoneList = timezoneList;
237
+ }
238
+
239
+ tp_inst.timezone = tp_inst._defaults.timezone;
240
+ tp_inst.hour = tp_inst._defaults.hour;
241
+ tp_inst.minute = tp_inst._defaults.minute;
242
+ tp_inst.second = tp_inst._defaults.second;
243
+ tp_inst.millisec = tp_inst._defaults.millisec;
244
+ tp_inst.ampm = '';
245
+ tp_inst.$input = $input;
246
+
247
+ if (o.altField) {
248
+ tp_inst.$altInput = $(o.altField).css({
249
+ cursor: 'pointer'
250
+ }).focus(function() {
251
+ $input.trigger("focus");
252
+ });
253
+ }
254
+
255
+ if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {
256
+ tp_inst._defaults.minDate = new Date();
257
+ }
258
+ if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {
259
+ tp_inst._defaults.maxDate = new Date();
260
+ }
261
+
262
+ // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
263
+ if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {
264
+ tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
265
+ }
266
+ if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {
267
+ tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
268
+ }
269
+ if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {
270
+ tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
271
+ }
272
+ if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {
273
+ tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
274
+ }
275
+ tp_inst.$input.bind('focus', function() {
276
+ tp_inst._onFocus();
277
+ });
278
+
279
+ return tp_inst;
280
+ },
281
+
282
+ /*
283
+ * add our sliders to the calendar
284
+ */
285
+ _addTimePicker: function(dp_inst) {
286
+ var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val();
287
+
288
+ this.timeDefined = this._parseTime(currDT);
289
+ this._limitMinMaxDateTime(dp_inst, false);
290
+ this._injectTimePicker();
291
+ },
292
+
293
+ /*
294
+ * parse the time string from input value or _setTime
295
+ */
296
+ _parseTime: function(timeString, withDate) {
297
+ if (!this.inst) {
298
+ this.inst = $.datepicker._getInst(this.$input[0]);
299
+ }
300
+
301
+ if (withDate || !this._defaults.timeOnly) {
302
+ var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
303
+ try {
304
+ var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);
305
+ if (!parseRes.timeObj) {
306
+ return false;
307
+ }
308
+ $.extend(this, parseRes.timeObj);
309
+ } catch (err) {
310
+ $.datepicker.log("Error parsing the date/time string: " + err +
311
+ "\ndate/time string = " + timeString +
312
+ "\ntimeFormat = " + this._defaults.timeFormat +
313
+ "\ndateFormat = " + dp_dateFormat);
314
+ return false;
315
+ }
316
+ return true;
317
+ } else {
318
+ var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);
319
+ if (!timeObj) {
320
+ return false;
321
+ }
322
+ $.extend(this, timeObj);
323
+ return true;
324
+ }
325
+ },
326
+
327
+ /*
328
+ * generate and inject html for timepicker into ui datepicker
329
+ */
330
+ _injectTimePicker: function() {
331
+ var $dp = this.inst.dpDiv,
332
+ o = this.inst.settings,
333
+ tp_inst = this,
334
+ litem = '',
335
+ uitem = '',
336
+ max = {},
337
+ gridSize = {},
338
+ size = null;
339
+
340
+ // Prevent displaying twice
341
+ if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) {
342
+ var noDisplay = ' style="display:none;"',
343
+ html = '<div class="ui-timepicker-div'+ (o.isRTL? ' ui-timepicker-rtl' : '') +'"><dl>' + '<dt class="ui_tpicker_time_label"' + ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' +
344
+ '<dd class="ui_tpicker_time"' + ((o.showTime) ? '' : noDisplay) + '></dd>';
345
+
346
+ // Create the markup
347
+ for(var i=0,l=this.units.length; i<l; i++){
348
+ litem = this.units[i];
349
+ uitem = litem.substr(0,1).toUpperCase() + litem.substr(1);
350
+ // Added by Peter Medeiros:
351
+ // - Figure out what the hour/minute/second max should be based on the step values.
352
+ // - Example: if stepMinute is 15, then minMax is 45.
353
+ max[litem] = parseInt((o[litem+'Max'] - ((o[litem+'Max'] - o[litem+'Min']) % o['step'+uitem])), 10);
354
+ gridSize[litem] = 0;
355
+
356
+ html += '<dt class="ui_tpicker_'+ litem +'_label"' + ((o['show'+uitem]) ? '' : noDisplay) + '>' + o[litem +'Text'] + '</dt>' +
357
+ '<dd class="ui_tpicker_'+ litem +'"><div class="ui_tpicker_'+ litem +'_slider"' + ((o['show'+uitem]) ? '' : noDisplay) + '></div>';
358
+
359
+ if (o['show'+uitem] && o[litem+'Grid'] > 0) {
360
+ html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
361
+
362
+ if(litem == 'hour'){
363
+ for (var h = o[litem+'Min']; h <= max[litem]; h += parseInt(o[litem+'Grid'], 10)) {
364
+ gridSize[litem]++;
365
+ var tmph = $.datepicker.formatTime(useAmpm(o.pickerTimeFormat || o.timeFormat)? 'hht':'HH', {hour:h}, o);
366
+ html += '<td data-for="'+litem+'">' + tmph + '</td>';
367
+ }
368
+ }
369
+ else{
370
+ for (var m = o[litem+'Min']; m <= max[litem]; m += parseInt(o[litem+'Grid'], 10)) {
371
+ gridSize[litem]++;
372
+ html += '<td data-for="'+litem+'">' + ((m < 10) ? '0' : '') + m + '</td>';
373
+ }
374
+ }
375
+
376
+ html += '</tr></table></div>';
377
+ }
378
+ html += '</dd>';
379
+ }
380
+
381
+ // Timezone
382
+ html += '<dt class="ui_tpicker_timezone_label"' + ((o.showTimezone) ? '' : noDisplay) + '>' + o.timezoneText + '</dt>';
383
+ html += '<dd class="ui_tpicker_timezone" ' + ((o.showTimezone) ? '' : noDisplay) + '></dd>';
384
+
385
+ // Create the elements from string
386
+ html += '</dl></div>';
387
+ var $tp = $(html);
388
+
389
+ // if we only want time picker...
390
+ if (o.timeOnly === true) {
391
+ $tp.prepend('<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + '</div>');
392
+ $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
393
+ }
394
+
395
+ // add sliders, adjust grids, add events
396
+ for(var i=0,l=tp_inst.units.length; i<l; i++){
397
+ litem = tp_inst.units[i];
398
+ uitem = litem.substr(0,1).toUpperCase() + litem.substr(1);
399
+
400
+ // add the slider
401
+ tp_inst[litem+'_slider'] = tp_inst.control.create(tp_inst, $tp.find('.ui_tpicker_'+litem+'_slider'), litem, tp_inst[litem], o[litem+'Min'], max[litem], o['step'+uitem]);
402
+
403
+ // adjust the grid and add click event
404
+ if (o['show'+uitem] && o[litem+'Grid'] > 0) {
405
+ size = 100 * gridSize[litem] * o[litem+'Grid'] / (max[litem] - o[litem+'Min']);
406
+ $tp.find('.ui_tpicker_'+litem+' table').css({
407
+ width: size + "%",
408
+ marginLeft: o.isRTL? '0' : ((size / (-2 * gridSize[litem])) + "%"),
409
+ marginRight: o.isRTL? ((size / (-2 * gridSize[litem])) + "%") : '0',
410
+ borderCollapse: 'collapse'
411
+ }).find("td").click(function(e){
412
+ var $t = $(this),
413
+ h = $t.html(),
414
+ n = parseInt(h.replace(/[^0-9]/g),10),
415
+ ap = h.replace(/[^apm]/ig),
416
+ f = $t.data('for'); // loses scope, so we use data-for
417
+
418
+ if(f == 'hour'){
419
+ if(ap.indexOf('p') !== -1 && n < 12){
420
+ n += 12;
421
+ }
422
+ else{
423
+ if(ap.indexOf('a') !== -1 && n === 12){
424
+ n = 0;
425
+ }
426
+ }
427
+ }
428
+
429
+ tp_inst.control.value(tp_inst, tp_inst[f+'_slider'], litem, n);
430
+
431
+ tp_inst._onTimeChange();
432
+ tp_inst._onSelectHandler();
433
+ })
434
+ .css({
435
+ cursor: 'pointer',
436
+ width: (100 / gridSize[litem]) + '%',
437
+ textAlign: 'center',
438
+ overflow: 'hidden'
439
+ });
440
+ } // end if grid > 0
441
+ } // end for loop
442
+
443
+ // Add timezone options
444
+ this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find("select");
445
+ $.fn.append.apply(this.timezone_select,
446
+ $.map(o.timezoneList, function(val, idx) {
447
+ return $("<option />").val(typeof val == "object" ? val.value : val).text(typeof val == "object" ? val.label : val);
448
+ }));
449
+ if (typeof(this.timezone) != "undefined" && this.timezone !== null && this.timezone !== "") {
450
+ var local_date = new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12);
451
+ var local_timezone = $.timepicker.timeZoneOffsetString(local_date);
452
+ if (local_timezone == this.timezone) {
453
+ selectLocalTimeZone(tp_inst);
454
+ } else {
455
+ this.timezone_select.val(this.timezone);
456
+ }
457
+ } else {
458
+ if (typeof(this.hour) != "undefined" && this.hour !== null && this.hour !== "") {
459
+ this.timezone_select.val(o.defaultTimezone);
460
+ } else {
461
+ selectLocalTimeZone(tp_inst);
462
+ }
463
+ }
464
+ this.timezone_select.change(function() {
465
+ tp_inst._defaults.useLocalTimezone = false;
466
+ tp_inst._onTimeChange();
467
+ });
468
+ // End timezone options
469
+
470
+ // inject timepicker into datepicker
471
+ var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
472
+ if ($buttonPanel.length) {
473
+ $buttonPanel.before($tp);
474
+ } else {
475
+ $dp.append($tp);
476
+ }
477
+
478
+ this.$timeObj = $tp.find('.ui_tpicker_time');
479
+
480
+ if (this.inst !== null) {
481
+ var timeDefined = this.timeDefined;
482
+ this._onTimeChange();
483
+ this.timeDefined = timeDefined;
484
+ }
485
+
486
+ // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
487
+ if (this._defaults.addSliderAccess) {
488
+ var sliderAccessArgs = this._defaults.sliderAccessArgs,
489
+ rtl = this._defaults.isRTL;
490
+ sliderAccessArgs.isRTL = rtl;
491
+
492
+ setTimeout(function() { // fix for inline mode
493
+ if ($tp.find('.ui-slider-access').length === 0) {
494
+ $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);
495
+
496
+ // fix any grids since sliders are shorter
497
+ var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);
498
+ if (sliderAccessWidth) {
499
+ $tp.find('table:visible').each(function() {
500
+ var $g = $(this),
501
+ oldWidth = $g.outerWidth(),
502
+ oldMarginLeft = $g.css(rtl? 'marginRight':'marginLeft').toString().replace('%', ''),
503
+ newWidth = oldWidth - sliderAccessWidth,
504
+ newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%',
505
+ css = { width: newWidth, marginRight: 0, marginLeft: 0 };
506
+ css[rtl? 'marginRight':'marginLeft'] = newMarginLeft;
507
+ $g.css(css);
508
+ });
509
+ }
510
+ }
511
+ }, 10);
512
+ }
513
+ // end slideAccess integration
514
+
515
+ }
516
+ },
517
+
518
+ /*
519
+ * This function tries to limit the ability to go outside the
520
+ * min/max date range
521
+ */
522
+ _limitMinMaxDateTime: function(dp_inst, adjustSliders) {
523
+ var o = this._defaults,
524
+ dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
525
+
526
+ if (!this._defaults.showTimepicker) {
527
+ return;
528
+ } // No time so nothing to check here
529
+
530
+ if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) {
531
+ var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),
532
+ minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
533
+
534
+ if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null) {
535
+ this.hourMinOriginal = o.hourMin;
536
+ this.minuteMinOriginal = o.minuteMin;
537
+ this.secondMinOriginal = o.secondMin;
538
+ this.millisecMinOriginal = o.millisecMin;
539
+ }
540
+
541
+ if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() == dp_date.getTime()) {
542
+ this._defaults.hourMin = minDateTime.getHours();
543
+ if (this.hour <= this._defaults.hourMin) {
544
+ this.hour = this._defaults.hourMin;
545
+ this._defaults.minuteMin = minDateTime.getMinutes();
546
+ if (this.minute <= this._defaults.minuteMin) {
547
+ this.minute = this._defaults.minuteMin;
548
+ this._defaults.secondMin = minDateTime.getSeconds();
549
+ if (this.second <= this._defaults.secondMin) {
550
+ this.second = this._defaults.secondMin;
551
+ this._defaults.millisecMin = minDateTime.getMilliseconds();
552
+ } else {
553
+ if (this.millisec < this._defaults.millisecMin) {
554
+ this.millisec = this._defaults.millisecMin;
555
+ }
556
+ this._defaults.millisecMin = this.millisecMinOriginal;
557
+ }
558
+ } else {
559
+ this._defaults.secondMin = this.secondMinOriginal;
560
+ this._defaults.millisecMin = this.millisecMinOriginal;
561
+ }
562
+ } else {
563
+ this._defaults.minuteMin = this.minuteMinOriginal;
564
+ this._defaults.secondMin = this.secondMinOriginal;
565
+ this._defaults.millisecMin = this.millisecMinOriginal;
566
+ }
567
+ } else {
568
+ this._defaults.hourMin = this.hourMinOriginal;
569
+ this._defaults.minuteMin = this.minuteMinOriginal;
570
+ this._defaults.secondMin = this.secondMinOriginal;
571
+ this._defaults.millisecMin = this.millisecMinOriginal;
572
+ }
573
+ }
574
+
575
+ if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) {
576
+ var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),
577
+ maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
578
+
579
+ if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null) {
580
+ this.hourMaxOriginal = o.hourMax;
581
+ this.minuteMaxOriginal = o.minuteMax;
582
+ this.secondMaxOriginal = o.secondMax;
583
+ this.millisecMaxOriginal = o.millisecMax;
584
+ }
585
+
586
+ if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() == dp_date.getTime()) {
587
+ this._defaults.hourMax = maxDateTime.getHours();
588
+ if (this.hour >= this._defaults.hourMax) {
589
+ this.hour = this._defaults.hourMax;
590
+ this._defaults.minuteMax = maxDateTime.getMinutes();
591
+ if (this.minute >= this._defaults.minuteMax) {
592
+ this.minute = this._defaults.minuteMax;
593
+ this._defaults.secondMax = maxDateTime.getSeconds();
594
+ } else if (this.second >= this._defaults.secondMax) {
595
+ this.second = this._defaults.secondMax;
596
+ this._defaults.millisecMax = maxDateTime.getMilliseconds();
597
+ } else {
598
+ if (this.millisec > this._defaults.millisecMax) {
599
+ this.millisec = this._defaults.millisecMax;
600
+ }
601
+ this._defaults.millisecMax = this.millisecMaxOriginal;
602
+ }
603
+ } else {
604
+ this._defaults.minuteMax = this.minuteMaxOriginal;
605
+ this._defaults.secondMax = this.secondMaxOriginal;
606
+ this._defaults.millisecMax = this.millisecMaxOriginal;
607
+ }
608
+ } else {
609
+ this._defaults.hourMax = this.hourMaxOriginal;
610
+ this._defaults.minuteMax = this.minuteMaxOriginal;
611
+ this._defaults.secondMax = this.secondMaxOriginal;
612
+ this._defaults.millisecMax = this.millisecMaxOriginal;
613
+ }
614
+ }
615
+
616
+ if (adjustSliders !== undefined && adjustSliders === true) {
617
+ var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10),
618
+ minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10),
619
+ secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10),
620
+ millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10);
621
+
622
+ if (this.hour_slider) {
623
+ this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax });
624
+ this.control.value(this, this.hour_slider, 'hour', this.hour);
625
+ }
626
+ if (this.minute_slider) {
627
+ this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax });
628
+ this.control.value(this, this.minute_slider, 'minute', this.minute);
629
+ }
630
+ if (this.second_slider) {
631
+ this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax });
632
+ this.control.value(this, this.second_slider, 'second', this.second);
633
+ }
634
+ if (this.millisec_slider) {
635
+ this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax });
636
+ this.control.value(this, this.millisec_slider, 'millisec', this.millisec);
637
+ }
638
+ }
639
+
640
+ },
641
+
642
+ /*
643
+ * when a slider moves, set the internal time...
644
+ * on time change is also called when the time is updated in the text field
645
+ */
646
+ _onTimeChange: function() {
647
+ var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false,
648
+ minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false,
649
+ second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false,
650
+ millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false,
651
+ timezone = (this.timezone_select) ? this.timezone_select.val() : false,
652
+ o = this._defaults,
653
+ pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,
654
+ pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;
655
+
656
+ if (typeof(hour) == 'object') {
657
+ hour = false;
658
+ }
659
+ if (typeof(minute) == 'object') {
660
+ minute = false;
661
+ }
662
+ if (typeof(second) == 'object') {
663
+ second = false;
664
+ }
665
+ if (typeof(millisec) == 'object') {
666
+ millisec = false;
667
+ }
668
+ if (typeof(timezone) == 'object') {
669
+ timezone = false;
670
+ }
671
+
672
+ if (hour !== false) {
673
+ hour = parseInt(hour, 10);
674
+ }
675
+ if (minute !== false) {
676
+ minute = parseInt(minute, 10);
677
+ }
678
+ if (second !== false) {
679
+ second = parseInt(second, 10);
680
+ }
681
+ if (millisec !== false) {
682
+ millisec = parseInt(millisec, 10);
683
+ }
684
+
685
+ var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];
686
+
687
+ // If the update was done in the input field, the input field should not be updated.
688
+ // If the update was done using the sliders, update the input field.
689
+ var hasChanged = (hour != this.hour || minute != this.minute || second != this.second || millisec != this.millisec
690
+ || (this.ampm.length > 0 && (hour < 12) != ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1))
691
+ || ((this.timezone === null && timezone != this.defaultTimezone) || (this.timezone !== null && timezone != this.timezone)));
692
+
693
+ if (hasChanged) {
694
+
695
+ if (hour !== false) {
696
+ this.hour = hour;
697
+ }
698
+ if (minute !== false) {
699
+ this.minute = minute;
700
+ }
701
+ if (second !== false) {
702
+ this.second = second;
703
+ }
704
+ if (millisec !== false) {
705
+ this.millisec = millisec;
706
+ }
707
+ if (timezone !== false) {
708
+ this.timezone = timezone;
709
+ }
710
+
711
+ if (!this.inst) {
712
+ this.inst = $.datepicker._getInst(this.$input[0]);
713
+ }
714
+
715
+ this._limitMinMaxDateTime(this.inst, true);
716
+ }
717
+ if (useAmpm(o.timeFormat)) {
718
+ this.ampm = ampm;
719
+ }
720
+
721
+ // Updates the time within the timepicker
722
+ this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o);
723
+ if (this.$timeObj) {
724
+ if(pickerTimeFormat === o.timeFormat){
725
+ this.$timeObj.text(this.formattedTime + pickerTimeSuffix);
726
+ }
727
+ else{
728
+ this.$timeObj.text($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix);
729
+ }
730
+ }
731
+
732
+ this.timeDefined = true;
733
+ if (hasChanged) {
734
+ this._updateDateTime();
735
+ }
736
+ },
737
+
738
+ /*
739
+ * call custom onSelect.
740
+ * bind to sliders slidestop, and grid click.
741
+ */
742
+ _onSelectHandler: function() {
743
+ var onSelect = this._defaults.onSelect || this.inst.settings.onSelect;
744
+ var inputEl = this.$input ? this.$input[0] : null;
745
+ if (onSelect && inputEl) {
746
+ onSelect.apply(inputEl, [this.formattedDateTime, this]);
747
+ }
748
+ },
749
+
750
+ /*
751
+ * update our input with the new date time..
752
+ */
753
+ _updateDateTime: function(dp_inst) {
754
+ dp_inst = this.inst || dp_inst;
755
+ var dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
756
+ dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
757
+ formatCfg = $.datepicker._getFormatConfig(dp_inst),
758
+ timeAvailable = dt !== null && this.timeDefined;
759
+ this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
760
+ var formattedDateTime = this.formattedDate;
761
+
762
+ /*
763
+ * remove following lines to force every changes in date picker to change the input value
764
+ * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.
765
+ * If the user manually empty the value in the input field, the date picker will never change selected value.
766
+ */
767
+ //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {
768
+ // return;
769
+ //}
770
+
771
+ if (this._defaults.timeOnly === true) {
772
+ formattedDateTime = this.formattedTime;
773
+ } else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) {
774
+ formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;
775
+ }
776
+
777
+ this.formattedDateTime = formattedDateTime;
778
+
779
+ if (!this._defaults.showTimepicker) {
780
+ this.$input.val(this.formattedDate);
781
+ } else if (this.$altInput && this._defaults.altFieldTimeOnly === true) {
782
+ this.$altInput.val(this.formattedTime);
783
+ this.$input.val(this.formattedDate);
784
+ } else if (this.$altInput) {
785
+ this.$input.val(formattedDateTime);
786
+ var altFormattedDateTime = '',
787
+ altSeparator = this._defaults.altSeparator ? this._defaults.altSeparator : this._defaults.separator,
788
+ altTimeSuffix = this._defaults.altTimeSuffix ? this._defaults.altTimeSuffix : this._defaults.timeSuffix;
789
+
790
+ if (this._defaults.altFormat) altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg);
791
+ else altFormattedDateTime = this.formattedDate;
792
+ if (altFormattedDateTime) altFormattedDateTime += altSeparator;
793
+ if (this._defaults.altTimeFormat) altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix;
794
+ else altFormattedDateTime += this.formattedTime + altTimeSuffix;
795
+ this.$altInput.val(altFormattedDateTime);
796
+ } else {
797
+ this.$input.val(formattedDateTime);
798
+ }
799
+
800
+ this.$input.trigger("change");
801
+ },
802
+
803
+ _onFocus: function() {
804
+ if (!this.$input.val() && this._defaults.defaultValue) {
805
+ this.$input.val(this._defaults.defaultValue);
806
+ var inst = $.datepicker._getInst(this.$input.get(0)),
807
+ tp_inst = $.datepicker._get(inst, 'timepicker');
808
+ if (tp_inst) {
809
+ if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) {
810
+ try {
811
+ $.datepicker._updateDatepicker(inst);
812
+ } catch (err) {
813
+ $.datepicker.log(err);
814
+ }
815
+ }
816
+ }
817
+ }
818
+ },
819
+
820
+ /*
821
+ * Small abstraction to control types
822
+ * We can add more, just be sure to follow the pattern: create, options, value
823
+ */
824
+ _controls: {
825
+ // slider methods
826
+ slider: {
827
+ create: function(tp_inst, obj, unit, val, min, max, step){
828
+ var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60
829
+ return obj.prop('slide', null).slider({
830
+ orientation: "horizontal",
831
+ value: rtl? val*-1 : val,
832
+ min: rtl? max*-1 : min,
833
+ max: rtl? min*-1 : max,
834
+ step: step,
835
+ slide: function(event, ui) {
836
+ tp_inst.control.value(tp_inst, $(this), unit, rtl? ui.value*-1:ui.value);
837
+ tp_inst._onTimeChange();
838
+ },
839
+ stop: function(event, ui) {
840
+ tp_inst._onSelectHandler();
841
+ }
842
+ });
843
+ },
844
+ options: function(tp_inst, obj, unit, opts, val){
845
+ if(tp_inst._defaults.isRTL){
846
+ if(typeof(opts) == 'string'){
847
+ if(opts == 'min' || opts == 'max'){
848
+ if(val !== undefined)
849
+ return obj.slider(opts, val*-1);
850
+ return Math.abs(obj.slider(opts));
851
+ }
852
+ return obj.slider(opts);
853
+ }
854
+ var min = opts.min,
855
+ max = opts.max;
856
+ opts.min = opts.max = null;
857
+ if(min !== undefined)
858
+ opts.max = min * -1;
859
+ if(max !== undefined)
860
+ opts.min = max * -1;
861
+ return obj.slider(opts);
862
+ }
863
+ if(typeof(opts) == 'string' && val !== undefined)
864
+ return obj.slider(opts, val);
865
+ return obj.slider(opts);
866
+ },
867
+ value: function(tp_inst, obj, unit, val){
868
+ if(tp_inst._defaults.isRTL){
869
+ if(val !== undefined)
870
+ return obj.slider('value', val*-1);
871
+ return Math.abs(obj.slider('value'));
872
+ }
873
+ if(val !== undefined)
874
+ return obj.slider('value', val);
875
+ return obj.slider('value');
876
+ }
877
+ },
878
+ // select methods
879
+ select: {
880
+ create: function(tp_inst, obj, unit, val, min, max, step){
881
+ var sel = '<select class="ui-timepicker-select" data-unit="'+ unit +'" data-min="'+ min +'" data-max="'+ max +'" data-step="'+ step +'">',
882
+ ul = tp_inst._defaults.timeFormat.indexOf('t') !== -1? 'toLowerCase':'toUpperCase',
883
+ m = 0;
884
+
885
+ for(var i=min; i<=max; i+=step){
886
+ sel += '<option value="'+ i +'"'+ (i==val? ' selected':'') +'>';
887
+ if(unit == 'hour' && useAmpm(tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat))
888
+ sel += $.datepicker.formatTime("hh TT", {hour:i}, tp_inst._defaults);
889
+ else if(unit == 'millisec' || i >= 10) sel += i;
890
+ else sel += '0'+ i.toString();
891
+ sel += '</option>';
892
+ }
893
+ sel += '</select>';
894
+
895
+ obj.children('select').remove();
896
+
897
+ $(sel).appendTo(obj).change(function(e){
898
+ tp_inst._onTimeChange();
899
+ tp_inst._onSelectHandler();
900
+ });
901
+
902
+ return obj;
903
+ },
904
+ options: function(tp_inst, obj, unit, opts, val){
905
+ var o = {},
906
+ $t = obj.children('select');
907
+ if(typeof(opts) == 'string'){
908
+ if(val === undefined)
909
+ return $t.data(opts);
910
+ o[opts] = val;
911
+ }
912
+ else o = opts;
913
+ return tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min || $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step'));
914
+ },
915
+ value: function(tp_inst, obj, unit, val){
916
+ var $t = obj.children('select');
917
+ if(val !== undefined)
918
+ return $t.val(val);
919
+ return $t.val();
920
+ }
921
+ }
922
+ } // end _controls
923
+
924
+ });
925
+
926
+ $.fn.extend({
927
+ /*
928
+ * shorthand just to use timepicker..
929
+ */
930
+ timepicker: function(o) {
931
+ o = o || {};
932
+ var tmp_args = Array.prototype.slice.call(arguments);
933
+
934
+ if (typeof o == 'object') {
935
+ tmp_args[0] = $.extend(o, {
936
+ timeOnly: true
937
+ });
938
+ }
939
+
940
+ return $(this).each(function() {
941
+ $.fn.datetimepicker.apply($(this), tmp_args);
942
+ });
943
+ },
944
+
945
+ /*
946
+ * extend timepicker to datepicker
947
+ */
948
+ datetimepicker: function(o) {
949
+ o = o || {};
950
+ var tmp_args = arguments;
951
+
952
+ if (typeof(o) == 'string') {
953
+ if (o == 'getDate') {
954
+ return $.fn.datepicker.apply($(this[0]), tmp_args);
955
+ } else {
956
+ return this.each(function() {
957
+ var $t = $(this);
958
+ $t.datepicker.apply($t, tmp_args);
959
+ });
960
+ }
961
+ } else {
962
+ return this.each(function() {
963
+ var $t = $(this);
964
+ $t.datepicker($.timepicker._newInst($t, o)._defaults);
965
+ });
966
+ }
967
+ }
968
+ });
969
+
970
+ /*
971
+ * Public Utility to parse date and time
972
+ */
973
+ $.datepicker.parseDateTime = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
974
+ var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);
975
+ if (parseRes.timeObj) {
976
+ var t = parseRes.timeObj;
977
+ parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);
978
+ }
979
+
980
+ return parseRes.date;
981
+ };
982
+
983
+ /*
984
+ * Public utility to parse time
985
+ */
986
+ $.datepicker.parseTime = function(timeFormat, timeString, options) {
987
+ var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {});
988
+
989
+ // Strict parse requires the timeString to match the timeFormat exactly
990
+ var strictParse = function(f, s, o){
991
+
992
+ // pattern for standard and localized AM/PM markers
993
+ var getPatternAmpm = function(amNames, pmNames) {
994
+ var markers = [];
995
+ if (amNames) {
996
+ $.merge(markers, amNames);
997
+ }
998
+ if (pmNames) {
999
+ $.merge(markers, pmNames);
1000
+ }
1001
+ markers = $.map(markers, function(val) {
1002
+ return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&');
1003
+ });
1004
+ return '(' + markers.join('|') + ')?';
1005
+ };
1006
+
1007
+ // figure out position of time elements.. cause js cant do named captures
1008
+ var getFormatPositions = function(timeFormat) {
1009
+ var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|t{1,2}|z|'.*?')/g),
1010
+ orders = {
1011
+ h: -1,
1012
+ m: -1,
1013
+ s: -1,
1014
+ l: -1,
1015
+ t: -1,
1016
+ z: -1
1017
+ };
1018
+
1019
+ if (finds) {
1020
+ for (var i = 0; i < finds.length; i++) {
1021
+ if (orders[finds[i].toString().charAt(0)] == -1) {
1022
+ orders[finds[i].toString().charAt(0)] = i + 1;
1023
+ }
1024
+ }
1025
+ }
1026
+ return orders;
1027
+ };
1028
+
1029
+ var regstr = '^' + f.toString()
1030
+ .replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[lz]|'.*?')/g, function (match) {
1031
+ switch (match.charAt(0).toLowerCase()) {
1032
+ case 'h': return '(\\d?\\d)';
1033
+ case 'm': return '(\\d?\\d)';
1034
+ case 's': return '(\\d?\\d)';
1035
+ case 'l': return '(\\d?\\d?\\d)';
1036
+ case 'z': return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?';
1037
+ case 't': return getPatternAmpm(o.amNames, o.pmNames);
1038
+ default: // literal escaped in quotes
1039
+ return '(' + match.replace(/\'/g, "").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function (m) { return "\\" + m; }) + ')?';
1040
+ }
1041
+ })
1042
+ .replace(/\s/g, '\\s?') +
1043
+ o.timeSuffix + '$',
1044
+ order = getFormatPositions(f),
1045
+ ampm = '',
1046
+ treg;
1047
+
1048
+ treg = s.match(new RegExp(regstr, 'i'));
1049
+
1050
+ var resTime = {
1051
+ hour: 0,
1052
+ minute: 0,
1053
+ second: 0,
1054
+ millisec: 0
1055
+ };
1056
+
1057
+ if (treg) {
1058
+ if (order.t !== -1) {
1059
+ if (treg[order.t] === undefined || treg[order.t].length === 0) {
1060
+ ampm = '';
1061
+ resTime.ampm = '';
1062
+ } else {
1063
+ ampm = $.inArray(treg[order.t].toUpperCase(), o.amNames) !== -1 ? 'AM' : 'PM';
1064
+ resTime.ampm = o[ampm == 'AM' ? 'amNames' : 'pmNames'][0];
1065
+ }
1066
+ }
1067
+
1068
+ if (order.h !== -1) {
1069
+ if (ampm == 'AM' && treg[order.h] == '12') {
1070
+ resTime.hour = 0; // 12am = 0 hour
1071
+ } else {
1072
+ if (ampm == 'PM' && treg[order.h] != '12') {
1073
+ resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12
1074
+ } else {
1075
+ resTime.hour = Number(treg[order.h]);
1076
+ }
1077
+ }
1078
+ }
1079
+
1080
+ if (order.m !== -1) {
1081
+ resTime.minute = Number(treg[order.m]);
1082
+ }
1083
+ if (order.s !== -1) {
1084
+ resTime.second = Number(treg[order.s]);
1085
+ }
1086
+ if (order.l !== -1) {
1087
+ resTime.millisec = Number(treg[order.l]);
1088
+ }
1089
+ if (order.z !== -1 && treg[order.z] !== undefined) {
1090
+ var tz = treg[order.z].toUpperCase();
1091
+ switch (tz.length) {
1092
+ case 1:
1093
+ // Z
1094
+ tz = o.timezoneIso8601 ? 'Z' : '+0000';
1095
+ break;
1096
+ case 5:
1097
+ // +hhmm
1098
+ if (o.timezoneIso8601) {
1099
+ tz = tz.substring(1) == '0000' ? 'Z' : tz.substring(0, 3) + ':' + tz.substring(3);
1100
+ }
1101
+ break;
1102
+ case 6:
1103
+ // +hh:mm
1104
+ if (!o.timezoneIso8601) {
1105
+ tz = tz == 'Z' || tz.substring(1) == '00:00' ? '+0000' : tz.replace(/:/, '');
1106
+ } else {
1107
+ if (tz.substring(1) == '00:00') {
1108
+ tz = 'Z';
1109
+ }
1110
+ }
1111
+ break;
1112
+ }
1113
+ resTime.timezone = tz;
1114
+ }
1115
+
1116
+
1117
+ return resTime;
1118
+ }
1119
+ return false;
1120
+ };// end strictParse
1121
+
1122
+ // First try JS Date, if that fails, use strictParse
1123
+ var looseParse = function(f,s,o){
1124
+ try{
1125
+ var d = new Date('2012-01-01 '+ s);
1126
+ return {
1127
+ hour: d.getHours(),
1128
+ minutes: d.getMinutes(),
1129
+ seconds: d.getSeconds(),
1130
+ millisec: d.getMilliseconds(),
1131
+ timezone: $.timepicker.timeZoneOffsetString(d)
1132
+ };
1133
+ }
1134
+ catch(err){
1135
+ try{
1136
+ return strictParse(f,s,o);
1137
+ }
1138
+ catch(err2){
1139
+ $.datepicker.log("Unable to parse \ntimeString: "+ s +"\ntimeFormat: "+ f);
1140
+ }
1141
+ }
1142
+ return false;
1143
+ }; // end looseParse
1144
+
1145
+ if(typeof o.parse === "function"){
1146
+ return o.parse(timeFormat, timeString, o)
1147
+ }
1148
+ if(o.parse === 'loose'){
1149
+ return looseParse(timeFormat, timeString, o);
1150
+ }
1151
+ return strictParse(timeFormat, timeString, o);
1152
+ };
1153
+
1154
+ /*
1155
+ * Public utility to format the time
1156
+ * format = string format of the time
1157
+ * time = a {}, not a Date() for timezones
1158
+ * options = essentially the regional[].. amNames, pmNames, ampm
1159
+ */
1160
+ $.datepicker.formatTime = function(format, time, options) {
1161
+ options = options || {};
1162
+ options = $.extend({}, $.timepicker._defaults, options);
1163
+ time = $.extend({
1164
+ hour: 0,
1165
+ minute: 0,
1166
+ second: 0,
1167
+ millisec: 0,
1168
+ timezone: '+0000'
1169
+ }, time);
1170
+
1171
+ var tmptime = format,
1172
+ ampmName = options.amNames[0],
1173
+ hour = parseInt(time.hour, 10);
1174
+
1175
+ if (hour > 11) {
1176
+ ampmName = options.pmNames[0];
1177
+ }
1178
+
1179
+ tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[lz]|('.*?'|".*?"))/g, function(match) {
1180
+ switch (match) {
1181
+ case 'HH':
1182
+ return ('0' + hour).slice(-2);
1183
+ case 'H':
1184
+ return hour;
1185
+ case 'hh':
1186
+ return ('0' + convert24to12(hour)).slice(-2);
1187
+ case 'h':
1188
+ return convert24to12(hour);
1189
+ case 'mm':
1190
+ return ('0' + time.minute).slice(-2);
1191
+ case 'm':
1192
+ return time.minute;
1193
+ case 'ss':
1194
+ return ('0' + time.second).slice(-2);
1195
+ case 's':
1196
+ return time.second;
1197
+ case 'l':
1198
+ return ('00' + time.millisec).slice(-3);
1199
+ case 'z':
1200
+ return time.timezone === null? options.defaultTimezone : time.timezone;
1201
+ case 'T':
1202
+ return ampmName.charAt(0).toUpperCase();
1203
+ case 'TT':
1204
+ return ampmName.toUpperCase();
1205
+ case 't':
1206
+ return ampmName.charAt(0).toLowerCase();
1207
+ case 'tt':
1208
+ return ampmName.toLowerCase();
1209
+ default:
1210
+ return match.replace(/\'/g, "") || "'";
1211
+ }
1212
+ });
1213
+
1214
+ tmptime = $.trim(tmptime);
1215
+ return tmptime;
1216
+ };
1217
+
1218
+ /*
1219
+ * the bad hack :/ override datepicker so it doesnt close on select
1220
+ // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
1221
+ */
1222
+ $.datepicker._base_selectDate = $.datepicker._selectDate;
1223
+ $.datepicker._selectDate = function(id, dateStr) {
1224
+ var inst = this._getInst($(id)[0]),
1225
+ tp_inst = this._get(inst, 'timepicker');
1226
+
1227
+ if (tp_inst) {
1228
+ tp_inst._limitMinMaxDateTime(inst, true);
1229
+ inst.inline = inst.stay_open = true;
1230
+ //This way the onSelect handler called from calendarpicker get the full dateTime
1231
+ this._base_selectDate(id, dateStr);
1232
+ inst.inline = inst.stay_open = false;
1233
+ this._notifyChange(inst);
1234
+ this._updateDatepicker(inst);
1235
+ } else {
1236
+ this._base_selectDate(id, dateStr);
1237
+ }
1238
+ };
1239
+
1240
+ /*
1241
+ * second bad hack :/ override datepicker so it triggers an event when changing the input field
1242
+ * and does not redraw the datepicker on every selectDate event
1243
+ */
1244
+ $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
1245
+ $.datepicker._updateDatepicker = function(inst) {
1246
+
1247
+ // don't popup the datepicker if there is another instance already opened
1248
+ var input = inst.input[0];
1249
+ if ($.datepicker._curInst && $.datepicker._curInst != inst && $.datepicker._datepickerShowing && $.datepicker._lastInput != input) {
1250
+ return;
1251
+ }
1252
+
1253
+ if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
1254
+
1255
+ this._base_updateDatepicker(inst);
1256
+
1257
+ // Reload the time control when changing something in the input text field.
1258
+ var tp_inst = this._get(inst, 'timepicker');
1259
+ if (tp_inst) {
1260
+ tp_inst._addTimePicker(inst);
1261
+
1262
+ if (tp_inst._defaults.useLocalTimezone) { //checks daylight saving with the new date.
1263
+ var date = new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay, 12);
1264
+ selectLocalTimeZone(tp_inst, date);
1265
+ tp_inst._onTimeChange();
1266
+ }
1267
+ }
1268
+ }
1269
+ };
1270
+
1271
+ /*
1272
+ * third bad hack :/ override datepicker so it allows spaces and colon in the input field
1273
+ */
1274
+ $.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
1275
+ $.datepicker._doKeyPress = function(event) {
1276
+ var inst = $.datepicker._getInst(event.target),
1277
+ tp_inst = $.datepicker._get(inst, 'timepicker');
1278
+
1279
+ if (tp_inst) {
1280
+ if ($.datepicker._get(inst, 'constrainInput')) {
1281
+ var ampm = useAmpm(tp_inst._defaults.timeFormat),
1282
+ dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
1283
+ datetimeChars = tp_inst._defaults.timeFormat.toString()
1284
+ .replace(/[hms]/g, '')
1285
+ .replace(/TT/g, ampm ? 'APM' : '')
1286
+ .replace(/Tt/g, ampm ? 'AaPpMm' : '')
1287
+ .replace(/tT/g, ampm ? 'AaPpMm' : '')
1288
+ .replace(/T/g, ampm ? 'AP' : '')
1289
+ .replace(/tt/g, ampm ? 'apm' : '')
1290
+ .replace(/t/g, ampm ? 'ap' : '') +
1291
+ " " + tp_inst._defaults.separator +
1292
+ tp_inst._defaults.timeSuffix +
1293
+ (tp_inst._defaults.showTimezone ? tp_inst._defaults.timezoneList.join('') : '') +
1294
+ (tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) +
1295
+ dateChars,
1296
+ chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
1297
+ return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);
1298
+ }
1299
+ }
1300
+
1301
+ return $.datepicker._base_doKeyPress(event);
1302
+ };
1303
+
1304
+ /*
1305
+ * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField
1306
+ */
1307
+ $.datepicker._base_updateAlternate = $.datepicker._updateAlternate;
1308
+ /* Update any alternate field to synchronise with the main field. */
1309
+ $.datepicker._updateAlternate = function(inst) {
1310
+ var tp_inst = this._get(inst, 'timepicker');
1311
+ if(tp_inst){
1312
+ var altField = tp_inst._defaults.altField;
1313
+ if (altField) { // update alternate field too
1314
+ var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat,
1315
+ date = this._getDate(inst),
1316
+ formatCfg = $.datepicker._getFormatConfig(inst),
1317
+ altFormattedDateTime = '',
1318
+ altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator,
1319
+ altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix,
1320
+ altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat;
1321
+
1322
+ altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix;
1323
+ if(!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly){
1324
+ if(tp_inst._defaults.altFormat)
1325
+ altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, (date === null ? new Date() : date), formatCfg) + altSeparator + altFormattedDateTime;
1326
+ else altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime;
1327
+ }
1328
+ $(altField).val(altFormattedDateTime);
1329
+ }
1330
+ }
1331
+ else{
1332
+ $.datepicker._base_updateAlternate(inst);
1333
+ }
1334
+ };
1335
+
1336
+ /*
1337
+ * Override key up event to sync manual input changes.
1338
+ */
1339
+ $.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
1340
+ $.datepicker._doKeyUp = function(event) {
1341
+ var inst = $.datepicker._getInst(event.target),
1342
+ tp_inst = $.datepicker._get(inst, 'timepicker');
1343
+
1344
+ if (tp_inst) {
1345
+ if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) {
1346
+ try {
1347
+ $.datepicker._updateDatepicker(inst);
1348
+ } catch (err) {
1349
+ $.datepicker.log(err);
1350
+ }
1351
+ }
1352
+ }
1353
+
1354
+ return $.datepicker._base_doKeyUp(event);
1355
+ };
1356
+
1357
+ /*
1358
+ * override "Today" button to also grab the time.
1359
+ */
1360
+ $.datepicker._base_gotoToday = $.datepicker._gotoToday;
1361
+ $.datepicker._gotoToday = function(id) {
1362
+ var inst = this._getInst($(id)[0]),
1363
+ $dp = inst.dpDiv;
1364
+ this._base_gotoToday(id);
1365
+ var tp_inst = this._get(inst, 'timepicker');
1366
+ selectLocalTimeZone(tp_inst);
1367
+ var now = new Date();
1368
+ this._setTime(inst, now);
1369
+ $('.ui-datepicker-today', $dp).click();
1370
+ };
1371
+
1372
+ /*
1373
+ * Disable & enable the Time in the datetimepicker
1374
+ */
1375
+ $.datepicker._disableTimepickerDatepicker = function(target) {
1376
+ var inst = this._getInst(target);
1377
+ if (!inst) {
1378
+ return;
1379
+ }
1380
+
1381
+ var tp_inst = this._get(inst, 'timepicker');
1382
+ $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
1383
+ if (tp_inst) {
1384
+ tp_inst._defaults.showTimepicker = false;
1385
+ tp_inst._updateDateTime(inst);
1386
+ }
1387
+ };
1388
+
1389
+ $.datepicker._enableTimepickerDatepicker = function(target) {
1390
+ var inst = this._getInst(target);
1391
+ if (!inst) {
1392
+ return;
1393
+ }
1394
+
1395
+ var tp_inst = this._get(inst, 'timepicker');
1396
+ $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
1397
+ if (tp_inst) {
1398
+ tp_inst._defaults.showTimepicker = true;
1399
+ tp_inst._addTimePicker(inst); // Could be disabled on page load
1400
+ tp_inst._updateDateTime(inst);
1401
+ }
1402
+ };
1403
+
1404
+ /*
1405
+ * Create our own set time function
1406
+ */
1407
+ $.datepicker._setTime = function(inst, date) {
1408
+ var tp_inst = this._get(inst, 'timepicker');
1409
+ if (tp_inst) {
1410
+ var defaults = tp_inst._defaults;
1411
+
1412
+ // calling _setTime with no date sets time to defaults
1413
+ tp_inst.hour = date ? date.getHours() : defaults.hour;
1414
+ tp_inst.minute = date ? date.getMinutes() : defaults.minute;
1415
+ tp_inst.second = date ? date.getSeconds() : defaults.second;
1416
+ tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec;
1417
+
1418
+ //check if within min/max times..
1419
+ tp_inst._limitMinMaxDateTime(inst, true);
1420
+
1421
+ tp_inst._onTimeChange();
1422
+ tp_inst._updateDateTime(inst);
1423
+ }
1424
+ };
1425
+
1426
+ /*
1427
+ * Create new public method to set only time, callable as $().datepicker('setTime', date)
1428
+ */
1429
+ $.datepicker._setTimeDatepicker = function(target, date, withDate) {
1430
+ var inst = this._getInst(target);
1431
+ if (!inst) {
1432
+ return;
1433
+ }
1434
+
1435
+ var tp_inst = this._get(inst, 'timepicker');
1436
+
1437
+ if (tp_inst) {
1438
+ this._setDateFromField(inst);
1439
+ var tp_date;
1440
+ if (date) {
1441
+ if (typeof date == "string") {
1442
+ tp_inst._parseTime(date, withDate);
1443
+ tp_date = new Date();
1444
+ tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
1445
+ } else {
1446
+ tp_date = new Date(date.getTime());
1447
+ }
1448
+ if (tp_date.toString() == 'Invalid Date') {
1449
+ tp_date = undefined;
1450
+ }
1451
+ this._setTime(inst, tp_date);
1452
+ }
1453
+ }
1454
+
1455
+ };
1456
+
1457
+ /*
1458
+ * override setDate() to allow setting time too within Date object
1459
+ */
1460
+ $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
1461
+ $.datepicker._setDateDatepicker = function(target, date) {
1462
+ var inst = this._getInst(target);
1463
+ if (!inst) {
1464
+ return;
1465
+ }
1466
+
1467
+ var tp_date = (date instanceof Date) ? new Date(date.getTime()) : date;
1468
+
1469
+ this._updateDatepicker(inst);
1470
+ this._base_setDateDatepicker.apply(this, arguments);
1471
+ this._setTimeDatepicker(target, tp_date, true);
1472
+ };
1473
+
1474
+ /*
1475
+ * override getDate() to allow getting time too within Date object
1476
+ */
1477
+ $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
1478
+ $.datepicker._getDateDatepicker = function(target, noDefault) {
1479
+ var inst = this._getInst(target);
1480
+ if (!inst) {
1481
+ return;
1482
+ }
1483
+
1484
+ var tp_inst = this._get(inst, 'timepicker');
1485
+
1486
+ if (tp_inst) {
1487
+ // if it hasn't yet been defined, grab from field
1488
+ if(inst.lastVal === undefined){
1489
+ this._setDateFromField(inst, noDefault);
1490
+ }
1491
+
1492
+ var date = this._getDate(inst);
1493
+ if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) {
1494
+ date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
1495
+ }
1496
+ return date;
1497
+ }
1498
+ return this._base_getDateDatepicker(target, noDefault);
1499
+ };
1500
+
1501
+ /*
1502
+ * override parseDate() because UI 1.8.14 throws an error about "Extra characters"
1503
+ * An option in datapicker to ignore extra format characters would be nicer.
1504
+ */
1505
+ $.datepicker._base_parseDate = $.datepicker.parseDate;
1506
+ $.datepicker.parseDate = function(format, value, settings) {
1507
+ var date;
1508
+ try {
1509
+ date = this._base_parseDate(format, value, settings);
1510
+ } catch (err) {
1511
+ // Hack! The error message ends with a colon, a space, and
1512
+ // the "extra" characters. We rely on that instead of
1513
+ // attempting to perfectly reproduce the parsing algorithm.
1514
+ date = this._base_parseDate(format, value.substring(0,value.length-(err.length-err.indexOf(':')-2)), settings);
1515
+ $.datepicker.log("Error parsing the date string: " + err + "\ndate string = " + value + "\ndate format = " + format);
1516
+ }
1517
+ return date;
1518
+ };
1519
+
1520
+ /*
1521
+ * override formatDate to set date with time to the input
1522
+ */
1523
+ $.datepicker._base_formatDate = $.datepicker._formatDate;
1524
+ $.datepicker._formatDate = function(inst, day, month, year) {
1525
+ var tp_inst = this._get(inst, 'timepicker');
1526
+ if (tp_inst) {
1527
+ tp_inst._updateDateTime(inst);
1528
+ return tp_inst.$input.val();
1529
+ }
1530
+ return this._base_formatDate(inst);
1531
+ };
1532
+
1533
+ /*
1534
+ * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
1535
+ */
1536
+ $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
1537
+ $.datepicker._optionDatepicker = function(target, name, value) {
1538
+ var inst = this._getInst(target),
1539
+ name_clone;
1540
+ if (!inst) {
1541
+ return null;
1542
+ }
1543
+
1544
+ var tp_inst = this._get(inst, 'timepicker');
1545
+ if (tp_inst) {
1546
+ var min = null,
1547
+ max = null,
1548
+ onselect = null,
1549
+ overrides = tp_inst._defaults.evnts,
1550
+ fns = {},
1551
+ prop;
1552
+ if (typeof name == 'string') { // if min/max was set with the string
1553
+ if (name === 'minDate' || name === 'minDateTime') {
1554
+ min = value;
1555
+ } else if (name === 'maxDate' || name === 'maxDateTime') {
1556
+ max = value;
1557
+ } else if (name === 'onSelect') {
1558
+ onselect = value;
1559
+ } else if (overrides.hasOwnProperty(name)) {
1560
+ if (typeof (value) === 'undefined') {
1561
+ return overrides[name];
1562
+ }
1563
+ fns[name] = value;
1564
+ name_clone = {}; //empty results in exiting function after overrides updated
1565
+ }
1566
+ } else if (typeof name == 'object') { //if min/max was set with the JSON
1567
+ if (name.minDate) {
1568
+ min = name.minDate;
1569
+ } else if (name.minDateTime) {
1570
+ min = name.minDateTime;
1571
+ } else if (name.maxDate) {
1572
+ max = name.maxDate;
1573
+ } else if (name.maxDateTime) {
1574
+ max = name.maxDateTime;
1575
+ }
1576
+ for (prop in overrides) {
1577
+ if (overrides.hasOwnProperty(prop) && name[prop]) {
1578
+ fns[prop] = name[prop];
1579
+ }
1580
+ }
1581
+ }
1582
+ for (prop in fns) {
1583
+ if (fns.hasOwnProperty(prop)) {
1584
+ overrides[prop] = fns[prop];
1585
+ if (!name_clone) { name_clone = $.extend({}, name);}
1586
+ delete name_clone[prop];
1587
+ }
1588
+ }
1589
+ if (name_clone && isEmptyObject(name_clone)) { return; }
1590
+ if (min) { //if min was set
1591
+ if (min === 0) {
1592
+ min = new Date();
1593
+ } else {
1594
+ min = new Date(min);
1595
+ }
1596
+ tp_inst._defaults.minDate = min;
1597
+ tp_inst._defaults.minDateTime = min;
1598
+ } else if (max) { //if max was set
1599
+ if (max === 0) {
1600
+ max = new Date();
1601
+ } else {
1602
+ max = new Date(max);
1603
+ }
1604
+ tp_inst._defaults.maxDate = max;
1605
+ tp_inst._defaults.maxDateTime = max;
1606
+ } else if (onselect) {
1607
+ tp_inst._defaults.onSelect = onselect;
1608
+ }
1609
+ }
1610
+ if (value === undefined) {
1611
+ return this._base_optionDatepicker.call($.datepicker, target, name);
1612
+ }
1613
+ return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
1614
+ };
1615
+ /*
1616
+ * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,
1617
+ * it will return false for all objects
1618
+ */
1619
+ var isEmptyObject = function(obj) {
1620
+ var prop;
1621
+ for (prop in obj) {
1622
+ if (obj.hasOwnProperty(obj)) {
1623
+ return false;
1624
+ }
1625
+ }
1626
+ return true;
1627
+ };
1628
+
1629
+ /*
1630
+ * jQuery extend now ignores nulls!
1631
+ */
1632
+ var extendRemove = function(target, props) {
1633
+ $.extend(target, props);
1634
+ for (var name in props) {
1635
+ if (props[name] === null || props[name] === undefined) {
1636
+ target[name] = props[name];
1637
+ }
1638
+ }
1639
+ return target;
1640
+ };
1641
+
1642
+ /*
1643
+ * Determine by the time format if should use ampm
1644
+ * Returns true if should use ampm, false if not
1645
+ */
1646
+ var useAmpm = function(timeFormat){
1647
+ return (timeFormat.indexOf('t') !== -1 && timeFormat.indexOf('h') !== -1);
1648
+ };
1649
+
1650
+ /*
1651
+ * Converts 24 hour format into 12 hour
1652
+ * Returns 12 hour without leading 0
1653
+ */
1654
+ var convert24to12 = function(hour) {
1655
+ if (hour > 12) {
1656
+ hour = hour - 12;
1657
+ }
1658
+
1659
+ if (hour == 0) {
1660
+ hour = 12;
1661
+ }
1662
+
1663
+ return String(hour);
1664
+ };
1665
+
1666
+ /*
1667
+ * Splits datetime string into date ans time substrings.
1668
+ * Throws exception when date can't be parsed
1669
+ * Returns [dateString, timeString]
1670
+ */
1671
+ var splitDateTime = function(dateFormat, dateTimeString, dateSettings, timeSettings) {
1672
+ try {
1673
+ // The idea is to get the number separator occurances in datetime and the time format requested (since time has
1674
+ // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.
1675
+ var separator = timeSettings && timeSettings.separator ? timeSettings.separator : $.timepicker._defaults.separator,
1676
+ format = timeSettings && timeSettings.timeFormat ? timeSettings.timeFormat : $.timepicker._defaults.timeFormat,
1677
+ timeParts = format.split(separator), // how many occurances of separator may be in our format?
1678
+ timePartsLen = timeParts.length,
1679
+ allParts = dateTimeString.split(separator),
1680
+ allPartsLen = allParts.length;
1681
+
1682
+ if (allPartsLen > 1) {
1683
+ return [
1684
+ allParts.splice(0,allPartsLen-timePartsLen).join(separator),
1685
+ allParts.splice(0,timePartsLen).join(separator)
1686
+ ];
1687
+ }
1688
+
1689
+ } catch (err) {
1690
+ $.datepicker.log('Could not split the date from the time. Please check the following datetimepicker options' +
1691
+ "\nthrown error: " + err +
1692
+ "\ndateTimeString" + dateTimeString +
1693
+ "\ndateFormat = " + dateFormat +
1694
+ "\nseparator = " + timeSettings.separator +
1695
+ "\ntimeFormat = " + timeSettings.timeFormat);
1696
+
1697
+ if (err.indexOf(":") >= 0) {
1698
+ // Hack! The error message ends with a colon, a space, and
1699
+ // the "extra" characters. We rely on that instead of
1700
+ // attempting to perfectly reproduce the parsing algorithm.
1701
+ var dateStringLength = dateTimeString.length - (err.length - err.indexOf(':') - 2),
1702
+ timeString = dateTimeString.substring(dateStringLength);
1703
+
1704
+ return [$.trim(dateTimeString.substring(0, dateStringLength)), $.trim(dateTimeString.substring(dateStringLength))];
1705
+
1706
+ } else {
1707
+ throw err;
1708
+ }
1709
+ }
1710
+ return [dateTimeString, ''];
1711
+ };
1712
+
1713
+ /*
1714
+ * Internal function to parse datetime interval
1715
+ * Returns: {date: Date, timeObj: Object}, where
1716
+ * date - parsed date without time (type Date)
1717
+ * timeObj = {hour: , minute: , second: , millisec: } - parsed time. Optional
1718
+ */
1719
+ var parseDateTimeInternal = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
1720
+ var date;
1721
+ var splitRes = splitDateTime(dateFormat, dateTimeString, dateSettings, timeSettings);
1722
+ date = $.datepicker._base_parseDate(dateFormat, splitRes[0], dateSettings);
1723
+ if (splitRes[1] !== '') {
1724
+ var timeString = splitRes[1],
1725
+ parsedTime = $.datepicker.parseTime(timeFormat, timeString, timeSettings);
1726
+
1727
+ if (parsedTime === null) {
1728
+ throw 'Wrong time format';
1729
+ }
1730
+ return {
1731
+ date: date,
1732
+ timeObj: parsedTime
1733
+ };
1734
+ } else {
1735
+ return {
1736
+ date: date
1737
+ };
1738
+ }
1739
+ };
1740
+
1741
+ /*
1742
+ * Internal function to set timezone_select to the local timezone
1743
+ */
1744
+ var selectLocalTimeZone = function(tp_inst, date) {
1745
+ if (tp_inst && tp_inst.timezone_select) {
1746
+ tp_inst._defaults.useLocalTimezone = true;
1747
+ var now = typeof date !== 'undefined' ? date : new Date();
1748
+ var tzoffset = $.timepicker.timeZoneOffsetString(now);
1749
+ if (tp_inst._defaults.timezoneIso8601) {
1750
+ tzoffset = tzoffset.substring(0, 3) + ':' + tzoffset.substring(3);
1751
+ }
1752
+ tp_inst.timezone_select.val(tzoffset);
1753
+ }
1754
+ };
1755
+
1756
+ /*
1757
+ * Create a Singleton Insance
1758
+ */
1759
+ $.timepicker = new Timepicker();
1760
+
1761
+ /**
1762
+ * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)
1763
+ * @param date
1764
+ * @return string
1765
+ */
1766
+ $.timepicker.timeZoneOffsetString = function(date) {
1767
+ var off = date.getTimezoneOffset() * -1,
1768
+ minutes = off % 60,
1769
+ hours = (off - minutes) / 60;
1770
+ return (off >= 0 ? '+' : '-') + ('0' + (hours * 101).toString()).substr(-2) + ('0' + (minutes * 101).toString()).substr(-2);
1771
+ };
1772
+
1773
+ /**
1774
+ * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to
1775
+ * enforce date range limits.
1776
+ * n.b. The input value must be correctly formatted (reformatting is not supported)
1777
+ * @param Element startTime
1778
+ * @param Element endTime
1779
+ * @param obj options Options for the timepicker() call
1780
+ * @return jQuery
1781
+ */
1782
+ $.timepicker.timeRange = function(startTime, endTime, options) {
1783
+ return $.timepicker.handleRange('timepicker', startTime, endTime, options);
1784
+ };
1785
+
1786
+ /**
1787
+ * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to
1788
+ * enforce date range limits.
1789
+ * @param Element startTime
1790
+ * @param Element endTime
1791
+ * @param obj options Options for the `timepicker()` call. Also supports `reformat`,
1792
+ * a boolean value that can be used to reformat the input values to the `dateFormat`.
1793
+ * @param string method Can be used to specify the type of picker to be added
1794
+ * @return jQuery
1795
+ */
1796
+ $.timepicker.dateTimeRange = function(startTime, endTime, options) {
1797
+ $.timepicker.dateRange(startTime, endTime, options, 'datetimepicker');
1798
+ };
1799
+
1800
+ /**
1801
+ * Calls `method` on the `startTime` and `endTime` elements, and configures them to
1802
+ * enforce date range limits.
1803
+ * @param Element startTime
1804
+ * @param Element endTime
1805
+ * @param obj options Options for the `timepicker()` call. Also supports `reformat`,
1806
+ * a boolean value that can be used to reformat the input values to the `dateFormat`.
1807
+ * @param string method Can be used to specify the type of picker to be added
1808
+ * @return jQuery
1809
+ */
1810
+ $.timepicker.dateRange = function(startTime, endTime, options, method) {
1811
+ method = method || 'datepicker';
1812
+ $.timepicker.handleRange(method, startTime, endTime, options);
1813
+ };
1814
+
1815
+ /**
1816
+ * Calls `method` on the `startTime` and `endTime` elements, and configures them to
1817
+ * enforce date range limits.
1818
+ * @param string method Can be used to specify the type of picker to be added
1819
+ * @param Element startTime
1820
+ * @param Element endTime
1821
+ * @param obj options Options for the `timepicker()` call. Also supports `reformat`,
1822
+ * a boolean value that can be used to reformat the input values to the `dateFormat`.
1823
+ * @return jQuery
1824
+ */
1825
+ $.timepicker.handleRange = function(method, startTime, endTime, options) {
1826
+ $.fn[method].call(startTime, $.extend({
1827
+ onClose: function(dateText, inst) {
1828
+ checkDates(this, endTime, dateText);
1829
+ },
1830
+ onSelect: function(selectedDateTime) {
1831
+ selected(this, endTime, 'minDate');
1832
+ }
1833
+ }, options, options.start));
1834
+ $.fn[method].call(endTime, $.extend({
1835
+ onClose: function(dateText, inst) {
1836
+ checkDates(this, startTime, dateText);
1837
+ },
1838
+ onSelect: function(selectedDateTime) {
1839
+ selected(this, startTime, 'maxDate');
1840
+ }
1841
+ }, options, options.end));
1842
+ // timepicker doesn't provide access to its 'timeFormat' option,
1843
+ // nor could I get datepicker.formatTime() to behave with times, so I
1844
+ // have disabled reformatting for timepicker
1845
+ if (method != 'timepicker' && options.reformat) {
1846
+ $([startTime, endTime]).each(function() {
1847
+ var format = $(this)[method].call($(this), 'option', 'dateFormat'),
1848
+ date = new Date($(this).val());
1849
+ if ($(this).val() && date) {
1850
+ $(this).val($.datepicker.formatDate(format, date));
1851
+ }
1852
+ });
1853
+ }
1854
+ checkDates(startTime, endTime, startTime.val());
1855
+
1856
+ function checkDates(changed, other, dateText) {
1857
+ if (other.val() && (new Date(startTime.val()) > new Date(endTime.val()))) {
1858
+ other.val(dateText);
1859
+ }
1860
+ }
1861
+ selected(startTime, endTime, 'minDate');
1862
+ selected(endTime, startTime, 'maxDate');
1863
+
1864
+ function selected(changed, other, option) {
1865
+ if (!$(changed).val()) {
1866
+ return;
1867
+ }
1868
+ var date = $(changed)[method].call($(changed), 'getDate');
1869
+ // timepicker doesn't implement 'getDate' and returns a jQuery
1870
+ if (date.getTime) {
1871
+ $(other)[method].call($(other), 'option', option, date);
1872
+ }
1873
+ }
1874
+ return $([startTime.get(0), endTime.get(0)]);
1875
+ };
1876
+
1877
+ /*
1878
+ * Keep up with the version
1879
+ */
1880
+ $.timepicker.version = "1.1.1";
1881
+
1882
+ })(jQuery);
languages/bulk-delete.pot CHANGED
@@ -1,240 +1,333 @@
1
- # Copyright (C) 2012 Bulk Delete
2
  # This file is distributed under the same license as the Bulk Delete package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Bulk Delete 2.0\n"
6
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/bulk-delete\n"
7
- "POT-Creation-Date: 2012-04-01 14:20:55+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: 2012-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
  "Language-Team: LANGUAGE <LL@li.org>\n"
14
 
15
- #: bulk-delete.php:296
16
- msgid "All the selected posts have been successfully deleted."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  msgstr ""
18
 
19
- #: bulk-delete.php:307
20
  msgid "WARNING: Posts deleted once cannot be retrieved back. Use with caution."
21
  msgstr ""
22
 
23
- #: bulk-delete.php:320
24
  msgid "By Type"
25
  msgstr ""
26
 
27
- #: bulk-delete.php:322
28
  msgid "Select the posts which you want to delete"
29
  msgstr ""
30
 
31
- #: bulk-delete.php:342
32
  msgid "All Drafts"
33
  msgstr ""
34
 
35
- #: bulk-delete.php:342
36
  msgid "Drafts"
37
  msgstr ""
38
 
39
- #: bulk-delete.php:349
40
  msgid "All Revisions"
41
  msgstr ""
42
 
43
- #: bulk-delete.php:349
44
  msgid "Revisions"
45
  msgstr ""
46
 
47
- #: bulk-delete.php:356
48
  msgid "All Pending posts"
49
  msgstr ""
50
 
51
- #: bulk-delete.php:356 bulk-delete.php:363 bulk-delete.php:370
52
- #: bulk-delete.php:448 bulk-delete.php:548 bulk-delete.php:652
53
  msgid "Posts"
54
  msgstr ""
55
 
56
- #: bulk-delete.php:363
57
  msgid "All scheduled posts"
58
  msgstr ""
59
 
60
- #: bulk-delete.php:370
61
  msgid "All private posts"
62
  msgstr ""
63
 
64
- #: bulk-delete.php:377
65
  msgid "All Pages"
66
  msgstr ""
67
 
68
- #: bulk-delete.php:377
69
  msgid "Pages"
70
  msgstr ""
71
 
72
- #: bulk-delete.php:384
73
  msgid ""
74
  "Delete these specific pages (Enter one post url (not post ids) per line)"
75
  msgstr ""
76
 
77
- #: bulk-delete.php:392 bulk-delete.php:465 bulk-delete.php:565
78
- #: bulk-delete.php:669
79
  msgid "Choose your filtering options"
80
  msgstr ""
81
 
82
- #: bulk-delete.php:398 bulk-delete.php:485 bulk-delete.php:585
83
- #: bulk-delete.php:689
84
  msgid "Move to Trash"
85
  msgstr ""
86
 
87
- #: bulk-delete.php:399 bulk-delete.php:486 bulk-delete.php:586
88
- #: bulk-delete.php:690
89
  msgid "Delete permanently"
90
  msgstr ""
91
 
92
- #: bulk-delete.php:406 bulk-delete.php:502 bulk-delete.php:602
93
- #: bulk-delete.php:706
94
  msgid "Only delete first "
95
  msgstr ""
96
 
97
- #: bulk-delete.php:407 bulk-delete.php:503 bulk-delete.php:603
98
- #: bulk-delete.php:707
99
  msgid "posts."
100
  msgstr ""
101
 
102
- #: bulk-delete.php:408 bulk-delete.php:504 bulk-delete.php:604
103
- #: bulk-delete.php:708
104
  msgid ""
105
  "Use this option if there are more than 1000 posts and the script timesout."
106
  msgstr ""
107
 
108
- #: bulk-delete.php:416 bulk-delete.php:511 bulk-delete.php:611
109
- #: bulk-delete.php:715
110
  msgid "Bulk Delete "
111
  msgstr ""
112
 
113
- #: bulk-delete.php:430
114
  msgid "By Category"
115
  msgstr ""
116
 
117
- #: bulk-delete.php:432
118
  msgid "Select the categories whose post you want to delete"
119
  msgstr ""
120
 
121
- #: bulk-delete.php:459
122
  msgid "All Categories"
123
  msgstr ""
124
 
125
- #: bulk-delete.php:474 bulk-delete.php:574 bulk-delete.php:678
126
  msgid "Only restrict to posts which are "
127
  msgstr ""
128
 
129
- #: bulk-delete.php:476 bulk-delete.php:576 bulk-delete.php:680
130
  msgid "older than"
131
  msgstr ""
132
 
133
- #: bulk-delete.php:477 bulk-delete.php:577 bulk-delete.php:681
134
  msgid "posted within last"
135
  msgstr ""
136
 
137
- #: bulk-delete.php:479 bulk-delete.php:579 bulk-delete.php:683
138
  msgid "days"
139
  msgstr ""
140
 
141
- #: bulk-delete.php:492 bulk-delete.php:592 bulk-delete.php:696
142
  msgid "Public posts"
143
  msgstr ""
144
 
145
- #: bulk-delete.php:493 bulk-delete.php:593 bulk-delete.php:697
146
  msgid "Private Posts"
147
  msgstr ""
148
 
149
- #: bulk-delete.php:529
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  msgid "By Tags"
151
  msgstr ""
152
 
153
- #: bulk-delete.php:532
154
  msgid "Select the tags whose post you want to delete"
155
  msgstr ""
156
 
157
- #: bulk-delete.php:559
158
  msgid "All Tags"
159
  msgstr ""
160
 
161
- #: bulk-delete.php:632
162
  msgid "By Taxonomies"
163
  msgstr ""
164
 
165
- #: bulk-delete.php:634
166
  msgid "Select the taxonomies whose post you want to delete"
167
  msgstr ""
168
 
169
- #: bulk-delete.php:663
170
  msgid "All Taxonomies"
171
  msgstr ""
172
 
173
- #: bulk-delete.php:731
174
  msgid "Debug Information"
175
  msgstr ""
176
 
177
- #: bulk-delete.php:733
178
  msgid ""
179
  "If you are seeing a blank page after clicking the Bulk Delete button, then "
180
  msgstr ""
181
 
182
- #: bulk-delete.php:733
183
  msgid "check out this FAQ"
184
  msgstr ""
185
 
186
- #: bulk-delete.php:734
187
  msgid "You also need need the following debug information."
188
  msgstr ""
189
 
190
- #: bulk-delete.php:737
191
  msgid "Available memory size "
192
  msgstr ""
193
 
194
- #: bulk-delete.php:741
195
  msgid "Script time out "
196
  msgstr ""
197
 
198
- #: bulk-delete.php:745
199
  msgid "Script input time "
200
  msgstr ""
201
 
202
- #: bulk-delete.php:752
203
  msgid ""
204
  "If you are looking to move posts in bulk, instead of deleting then try out "
205
  "my "
206
  msgstr ""
207
 
208
- #: bulk-delete.php:752
209
  msgid "Bulk Move Plugin"
210
  msgstr ""
211
 
212
- #: bulk-delete.php:857
213
- msgid "Manage"
214
- msgstr ""
215
-
216
- #: bulk-delete.php:870
217
  msgid "plugin"
218
  msgstr ""
219
 
220
- #: bulk-delete.php:870
221
  msgid "Version"
222
  msgstr ""
223
 
224
- #: bulk-delete.php:870
225
  msgid "by"
226
  msgstr ""
227
 
 
 
 
 
228
  #: bulk-delete.php:931
229
- msgid "Are you sure you want to delete all the selected posts"
 
230
  msgstr ""
231
 
232
- #: bulk-delete.php:933
233
- msgid "Please select at least one"
 
 
234
  msgstr ""
235
 
236
- #. Plugin Name of the plugin/theme
237
- msgid "Bulk Delete"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  msgstr ""
239
 
240
  #. Plugin URI of the plugin/theme
@@ -243,7 +336,8 @@ msgstr ""
243
 
244
  #. Description of the plugin/theme
245
  msgid ""
246
- "Bulk delete posts from selected categories or tags. Use it with caution."
 
247
  msgstr ""
248
 
249
  #. Author of the plugin/theme
1
+ # Copyright (C) 2013 Bulk Delete
2
  # This file is distributed under the same license as the Bulk Delete package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Bulk Delete 3.0\n"
6
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/bulk-delete\n"
7
+ "POT-Creation-Date: 2013-04-27 12:17:49+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: 2013-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
  "Language-Team: LANGUAGE <LL@li.org>\n"
14
 
15
+ #. #-#-#-#-# bulk-delete.pot (Bulk Delete 3.0) #-#-#-#-#
16
+ #. Plugin Name of the plugin/theme
17
+ #: bulk-delete.php:100 bulk-delete.php:171
18
+ msgid "Bulk Delete"
19
+ msgstr ""
20
+
21
+ #: bulk-delete.php:101 bulk-delete.php:674
22
+ msgid "Bulk Delete Schedules"
23
+ msgstr ""
24
+
25
+ #: bulk-delete.php:124
26
+ msgid "Are you sure you want to delete all the selected posts"
27
+ msgstr ""
28
+
29
+ #: bulk-delete.php:125
30
+ msgid "Please select at least one"
31
+ msgstr ""
32
+
33
+ #: bulk-delete.php:142
34
+ msgid "Manage"
35
+ msgstr ""
36
+
37
+ #: bulk-delete.php:156
38
+ msgid "Buy Addons"
39
  msgstr ""
40
 
41
+ #: bulk-delete.php:167
42
  msgid "WARNING: Posts deleted once cannot be retrieved back. Use with caution."
43
  msgstr ""
44
 
45
+ #: bulk-delete.php:178
46
  msgid "By Type"
47
  msgstr ""
48
 
49
+ #: bulk-delete.php:180
50
  msgid "Select the posts which you want to delete"
51
  msgstr ""
52
 
53
+ #: bulk-delete.php:200
54
  msgid "All Drafts"
55
  msgstr ""
56
 
57
+ #: bulk-delete.php:200
58
  msgid "Drafts"
59
  msgstr ""
60
 
61
+ #: bulk-delete.php:207
62
  msgid "All Revisions"
63
  msgstr ""
64
 
65
+ #: bulk-delete.php:207
66
  msgid "Revisions"
67
  msgstr ""
68
 
69
+ #: bulk-delete.php:214
70
  msgid "All Pending posts"
71
  msgstr ""
72
 
73
+ #: bulk-delete.php:214 bulk-delete.php:221 bulk-delete.php:228
74
+ #: bulk-delete.php:306 bulk-delete.php:431 bulk-delete.php:535
75
  msgid "Posts"
76
  msgstr ""
77
 
78
+ #: bulk-delete.php:221
79
  msgid "All scheduled posts"
80
  msgstr ""
81
 
82
+ #: bulk-delete.php:228
83
  msgid "All private posts"
84
  msgstr ""
85
 
86
+ #: bulk-delete.php:235
87
  msgid "All Pages"
88
  msgstr ""
89
 
90
+ #: bulk-delete.php:235
91
  msgid "Pages"
92
  msgstr ""
93
 
94
+ #: bulk-delete.php:242
95
  msgid ""
96
  "Delete these specific pages (Enter one post url (not post ids) per line)"
97
  msgstr ""
98
 
99
+ #: bulk-delete.php:250 bulk-delete.php:323 bulk-delete.php:448
100
+ #: bulk-delete.php:552
101
  msgid "Choose your filtering options"
102
  msgstr ""
103
 
104
+ #: bulk-delete.php:256 bulk-delete.php:343 bulk-delete.php:468
105
+ #: bulk-delete.php:572
106
  msgid "Move to Trash"
107
  msgstr ""
108
 
109
+ #: bulk-delete.php:257 bulk-delete.php:344 bulk-delete.php:469
110
+ #: bulk-delete.php:573
111
  msgid "Delete permanently"
112
  msgstr ""
113
 
114
+ #: bulk-delete.php:264 bulk-delete.php:360 bulk-delete.php:485
115
+ #: bulk-delete.php:589
116
  msgid "Only delete first "
117
  msgstr ""
118
 
119
+ #: bulk-delete.php:265 bulk-delete.php:361 bulk-delete.php:486
120
+ #: bulk-delete.php:590
121
  msgid "posts."
122
  msgstr ""
123
 
124
+ #: bulk-delete.php:266 bulk-delete.php:362 bulk-delete.php:487
125
+ #: bulk-delete.php:591
126
  msgid ""
127
  "Use this option if there are more than 1000 posts and the script timesout."
128
  msgstr ""
129
 
130
+ #: bulk-delete.php:274 bulk-delete.php:394 bulk-delete.php:494
131
+ #: bulk-delete.php:598
132
  msgid "Bulk Delete "
133
  msgstr ""
134
 
135
+ #: bulk-delete.php:288
136
  msgid "By Category"
137
  msgstr ""
138
 
139
+ #: bulk-delete.php:290
140
  msgid "Select the categories whose post you want to delete"
141
  msgstr ""
142
 
143
+ #: bulk-delete.php:317
144
  msgid "All Categories"
145
  msgstr ""
146
 
147
+ #: bulk-delete.php:332 bulk-delete.php:457 bulk-delete.php:561
148
  msgid "Only restrict to posts which are "
149
  msgstr ""
150
 
151
+ #: bulk-delete.php:334 bulk-delete.php:459 bulk-delete.php:563
152
  msgid "older than"
153
  msgstr ""
154
 
155
+ #: bulk-delete.php:335 bulk-delete.php:460 bulk-delete.php:564
156
  msgid "posted within last"
157
  msgstr ""
158
 
159
+ #: bulk-delete.php:337 bulk-delete.php:462 bulk-delete.php:566
160
  msgid "days"
161
  msgstr ""
162
 
163
+ #: bulk-delete.php:350 bulk-delete.php:475 bulk-delete.php:579
164
  msgid "Public posts"
165
  msgstr ""
166
 
167
+ #: bulk-delete.php:351 bulk-delete.php:476 bulk-delete.php:580
168
  msgid "Private Posts"
169
  msgstr ""
170
 
171
+ #: bulk-delete.php:368
172
+ msgid "Delete now"
173
+ msgstr ""
174
+
175
+ #: bulk-delete.php:369 include/class-cron-list-table.php:73
176
+ msgid "Schedule"
177
+ msgstr ""
178
+
179
+ #: bulk-delete.php:370
180
+ msgid "repeat "
181
+ msgstr ""
182
+
183
+ #: bulk-delete.php:372
184
+ msgid "Don't repeat"
185
+ msgstr ""
186
+
187
+ #: bulk-delete.php:382
188
+ msgid "Only available in Pro Addon"
189
+ msgstr ""
190
+
191
+ #: bulk-delete.php:387
192
+ msgid "Enter time in Y-m-d H:i:s format or enter now to use current time"
193
+ msgstr ""
194
+
195
+ #: bulk-delete.php:412
196
  msgid "By Tags"
197
  msgstr ""
198
 
199
+ #: bulk-delete.php:415
200
  msgid "Select the tags whose post you want to delete"
201
  msgstr ""
202
 
203
+ #: bulk-delete.php:442
204
  msgid "All Tags"
205
  msgstr ""
206
 
207
+ #: bulk-delete.php:515
208
  msgid "By Taxonomies"
209
  msgstr ""
210
 
211
+ #: bulk-delete.php:517
212
  msgid "Select the taxonomies whose post you want to delete"
213
  msgstr ""
214
 
215
+ #: bulk-delete.php:546
216
  msgid "All Taxonomies"
217
  msgstr ""
218
 
219
+ #: bulk-delete.php:614
220
  msgid "Debug Information"
221
  msgstr ""
222
 
223
+ #: bulk-delete.php:616
224
  msgid ""
225
  "If you are seeing a blank page after clicking the Bulk Delete button, then "
226
  msgstr ""
227
 
228
+ #: bulk-delete.php:616
229
  msgid "check out this FAQ"
230
  msgstr ""
231
 
232
+ #: bulk-delete.php:617
233
  msgid "You also need need the following debug information."
234
  msgstr ""
235
 
236
+ #: bulk-delete.php:620
237
  msgid "Available memory size "
238
  msgstr ""
239
 
240
+ #: bulk-delete.php:624
241
  msgid "Script time out "
242
  msgstr ""
243
 
244
+ #: bulk-delete.php:628
245
  msgid "Script input time "
246
  msgstr ""
247
 
248
+ #: bulk-delete.php:635
249
  msgid ""
250
  "If you are looking to move posts in bulk, instead of deleting then try out "
251
  "my "
252
  msgstr ""
253
 
254
+ #: bulk-delete.php:635
255
  msgid "Bulk Move Plugin"
256
  msgstr ""
257
 
258
+ #: bulk-delete.php:652
 
 
 
 
259
  msgid "plugin"
260
  msgstr ""
261
 
262
+ #: bulk-delete.php:652
263
  msgid "Version"
264
  msgstr ""
265
 
266
+ #: bulk-delete.php:652
267
  msgid "by"
268
  msgstr ""
269
 
270
+ #: bulk-delete.php:919
271
+ msgid "All the selected posts have been successfully deleted."
272
+ msgstr ""
273
+
274
  #: bulk-delete.php:931
275
+ msgctxt "Cron table date format"
276
+ msgid "M j, Y @ G:i"
277
  msgstr ""
278
 
279
+ #: include/class-cron-list-table.php:31
280
+ msgid ""
281
+ "This is the list of jobs that are currently scheduled for auto deleting "
282
+ "posts in Bulk Delete Plugin."
283
  msgstr ""
284
 
285
+ #: include/class-cron-list-table.php:40
286
+ msgid "Note: "
287
+ msgstr ""
288
+
289
+ #: include/class-cron-list-table.php:42
290
+ msgid ""
291
+ "Scheduling auto post deletion is available only when you buy pro addons."
292
+ msgstr ""
293
+
294
+ #: include/class-cron-list-table.php:45
295
+ msgid "The following are the list of pro addons that are currently available."
296
+ msgstr ""
297
+
298
+ #: include/class-cron-list-table.php:47
299
+ msgid "Bulk Delete Schedule Categories"
300
+ msgstr ""
301
+
302
+ #: include/class-cron-list-table.php:49
303
+ msgid ""
304
+ "This addon adds the ability to schedule auto delete of categories. The cost "
305
+ "of this addon is $15. You can buy it through paypal by clicking the below "
306
+ "button."
307
+ msgstr ""
308
+
309
+ #: include/class-cron-list-table.php:61
310
+ msgid "More addons coming soon"
311
+ msgstr ""
312
+
313
+ #: include/class-cron-list-table.php:72
314
+ msgid "Next Due (GMT/UTC)"
315
+ msgstr ""
316
+
317
+ #: include/class-cron-list-table.php:74
318
+ msgid "Type"
319
+ msgstr ""
320
+
321
+ #: include/class-cron-list-table.php:75
322
+ msgid "Options"
323
+ msgstr ""
324
+
325
+ #: include/class-cron-list-table.php:121
326
+ msgid "Delete"
327
+ msgstr ""
328
+
329
+ #: include/class-cron-list-table.php:146
330
+ msgid "You have not scheduled any bulk delete jobs."
331
  msgstr ""
332
 
333
  #. Plugin URI of the plugin/theme
336
 
337
  #. Description of the plugin/theme
338
  msgid ""
339
+ "Bulk delete posts from selected categories, tags or custom taxonomies. Use "
340
+ "it with caution."
341
  msgstr ""
342
 
343
  #. Author of the plugin/theme
readme.txt CHANGED
@@ -1,27 +1,100 @@
1
  === Bulk Delete ===
2
- Contributors: sudar
3
- Tags: post, comment, delete, bulk, draft, revision, page
4
- Requires at least: 2.0
5
- Tested up to: 3.5
6
- Donate Link: http://sudarmuthu.com/if-you-wanna-thank-me
7
- Stable tag: 2.2.2
8
-
9
- Bulk delete posts from selected categories or tags
10
 
11
  == Description ==
12
 
13
  Bulk Delete is a WordPress Plugin which can be used to delete posts in bulk from selected categories, tags or custom taxonomies. This Plugin can also delete all drafts, post revisions or pages.
14
 
15
- More details about the Plugin can be found at the [Plugins Home page][1].
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
  If you looking for just moving posts, instead of deleting, then use [Bulk Move Plugin][2] instead.
18
 
19
- ### Translation
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
- * Dutch (Thanks Rene of [WordPress WPwebshop][3])
22
- * Brazilian Portuguese (Thanks Marcelo of [Criacao de Sites em Ribeirao Preto][4])
23
- * German (Thanks Jenny Beelens of [professionaltranslation.com][8])
24
- * Turkish Portuguese (Thanks [Bahadir Yildiz][9])
25
  * Spanish (Thanks Brian Flores of [InMotion Hosting][10])
26
  * Italian (Thanks Paolo Gabrielli)
27
  * Bulgarian (Thanks Nikolay Nikolov of [Skype Fan Blog][11])
@@ -30,29 +103,22 @@ If you looking for just moving posts, instead of deleting, then use [Bulk Move P
30
  * Hindi (Thanks Love Chandel)
31
  * Serbian (Thanks Diana)
32
 
33
- ### Support
34
-
35
- Support for the Plugin is available from the [Plugins home page][1]. If you have any questions or suggestions, do leave a comment there or contact me in [twitter][5].
36
-
37
- ### Links
38
 
39
- * [Plugin home page][1]
40
- * [Author's Blog][6]
41
- * [Other Plugins by the author][7]
42
-
43
- [1]: http://sudarmuthu.com/wordpress/bulk-delete
44
- [2]: http://sudarmuthu.com/wordpress/bulk-move
45
- [3]: http://wpwebshop.com/premium-wordpress-plugins/
46
- [4]: http://www.techload.com.br/
47
- [5]: http://twitter.com/sudarmuthu
48
- [6]: http://sudarmuthu.com/blog
49
- [7]: http://sudarmuthu.com/wordpress
50
- [8]: http://www.professionaltranslation.com
51
- [9]: http://www.matematik.us
52
  [10]: http://www.inmotionhosting.com/
53
  [11]: http://en.chat4o.com/
54
  [12]: http://www.weblancer.net/users/Kirky/
55
  [13]: http://www.host1free.com
 
 
 
 
 
 
 
 
 
 
56
 
57
  == Installation ==
58
 
@@ -66,106 +132,114 @@ This can happen if you have huge number of posts and your server is very underpo
66
 
67
  In particular try to change the following settings
68
 
69
- * max_execution_time = 600 ; Maximum execution time of each script, in seconds
70
- * max_input_time = 30; Maximum amount of time each script may spend parsing request data
71
- * memory_limit = 256M ; Maximum amount of memory a script may consume (8MB)
72
 
73
- Additional FAQ and troubleshooting guide can be found in the [Plugins homepage](http://sudarmuthu.com/bulk-delete)
74
 
75
- == Screenshot ==
76
 
77
- 1. Delete posts based on type
78
 
79
- 2. Delete posts based on date, post visibility or choose to move them to trash or delete permanently
80
 
81
- 3. Delete Posts by Categories or Tags
82
 
83
- 4. Delete Posts by Custom taxonomies
84
 
85
- == Changelog ==
86
 
87
- ###v0.1 (2009-02-02)
88
 
89
- * first version
90
 
91
- ###v0.2 (2009-02-03)
92
 
93
- * Fixed issues with paging
94
 
95
- ###v0.3 (2009-04-05)
 
 
96
 
97
- * Prevented drafts from deleted when only posts are selected
 
98
 
99
- ###v0.4 (2009-07-05)
 
100
 
101
- * Added option to delete by date.
 
 
102
 
103
- ###v0.5 (2009-07-21)
104
- * Added option to delete all pending posts.
 
105
 
106
- ###v0.6 (2009-07-22)
107
- * Added option to delete all scheduled posts.
 
 
108
 
109
- ###v0.7 (2010-02-21)
110
- * Added an option to delete posts directly or send them to trash.
111
- * Added support for translation.
 
112
 
113
- ###v0.8 (2010-03-17)
114
- * Added support for private posts.
115
 
116
- ###v1.0 (2010-06-19)
117
- * Proper handling of limits.
118
 
119
- ###v1.1 (2011-01-22)
120
- * Added support to delete posts by custom taxonomies
121
- * Added Dutch Translation
122
- * Added Brazilian Portuguese Translation
123
 
124
- ###v1.2 (2011-02-06)
125
- * Added some optimization to handle huge number of posts in underpowered servers
 
 
 
126
 
127
- ###v1.3 (2011-05-11)
128
  * Added German translations
129
 
130
- ###v1.4 (2011-08-25)
131
- * Added Turkish translations
132
 
133
- ###v1.5 (2011-11-13)
134
- * Added Spanish translations
 
 
135
 
136
- ###v1.6 (2011-11-28)
137
- * Added Italian translations
138
 
139
- ###v1.7 (2012-01-12)
140
- * Added Bulgarian translations
141
 
142
- ###v1.8 (2012-01-31)
143
- * Added roles and capabilities for menu
 
144
 
145
- ###v1.9 (2012-03-16)
146
- * Added support for deleting by permalink. Credit Martin Capodici
147
- * Fixed issues with translations
148
- * Added Russian translations
149
 
150
- ###v2.0 (2012-04-01) Dev Time: 10 hours
151
- * Fixed a major issue in how dates were handled.
152
- * Major UI revamp
153
- * Added debug information and support urls
154
 
155
- ###v2.1 (2012-04-07) Dev Time: 1 hour
156
- * Fixed CSS issues in IE
157
- * Added Lithuanian translations
158
 
159
- ### v2.2 (2012-07-11) (Dev time: 0.5 hour)
160
- * Added Hindi translations
161
- * Added checks to see if elements are present in the array before accessing them.
162
 
163
- ### v2.2.1 (2012-10-28) (Dev time: 0.5 hour)
164
- * Added Serbian translations
165
 
166
- ### v2.2.2 (2012-12-20) (Dev time: 0.5 hour)
167
- * Removed unused wpdb->prepare() function calls
168
 
169
- ==Readme Generator==
170
 
171
  This Readme file was generated using <a href = 'http://sudarmuthu.com/wordpress/wp-readme'>wp-readme</a>, which generates readme files for WordPress Plugins.
1
  === Bulk Delete ===
2
+ Contributors: sudar
3
+ Tags: post, comment, delete, bulk, draft, revision, page
4
+ Requires at least: 2.0
5
+ Tested up to: 3.5.1
6
+ Donate Link: http://sudarmuthu.com/if-you-wanna-thank-me
7
+ Stable tag: 3.0
8
+
9
+ Bulk delete posts from selected categories, tags or custom taxonomies
10
 
11
  == Description ==
12
 
13
  Bulk Delete is a WordPress Plugin which can be used to delete posts in bulk from selected categories, tags or custom taxonomies. This Plugin can also delete all drafts, post revisions or pages.
14
 
15
+ ### Features
16
+
17
+ This Plugin supports the following bulk delete options
18
+
19
+ - Delete posts by category
20
+ - Delete posts by tags
21
+ - Delete posts by custom taxonomies
22
+ - Delete posts by url
23
+ - Delete all pages
24
+ - Delete all post revisions
25
+ - Delete all pending posts
26
+ - Delete all private posts
27
+ - Delete all drafts
28
+
29
+ All the above options support the following filters
30
+
31
+ - Post date greater than X days
32
+ - Post date less than X days
33
+ - Only public posts
34
+ - Only private posts
35
+ - Restrict to first Y posts
36
+ - Schedule deletion of posts automatically (Available as a Pro addon)
37
+
38
+ As you can see, the Plugin provide comprehensive options and filters to perform bulk deletion.
39
 
40
  If you looking for just moving posts, instead of deleting, then use [Bulk Move Plugin][2] instead.
41
 
42
+ ### Pro Addons
43
+
44
+ The following are the list of pro addons that are currently available.
45
+
46
+ #### Bulk Delete Schedule Categories
47
+
48
+ This addon adds the ability to schedule auto delete of posts based on categories. This will be really useful, if you have to delete posts based on categories on a regular basis.
49
+
50
+ The cost of this addon is $15 and you can buy it through [paypal](http://sudarmuthu.com/out/bulk-delete-category-addon).
51
+
52
+ ### Development
53
+
54
+ The development of the Plugin happens over at [github][6]. If you want to contribute to the Plugin, fork the [project at github][6] and send me a pull request.
55
+
56
+ If you are not familiar with either git or Github then refer to this [guide to see how fork and send pull request](http://sudarmuthu.com/blog/contributing-to-project-hosted-in-github).
57
+
58
+ If you are looking for ideas, then you can start with one of the following TODO items :)
59
+
60
+ ### TODO
61
+
62
+ The following are the features that I am thinking of adding to the Plugin, when I get some free time. If you have any feature request or want to increase the priority of a particular feature, then let me know.
63
+
64
+ - Bulk delete based on the presence/absence of a word
65
+ - Bulk Delete empty posts
66
+ - Bulk Delete posts based on users
67
+ - Bulk Delete by custom post types
68
+ - Delete images that are used by the posts that are being deleted
69
+ - Expandable/collapsible taxonomies
70
+ - Bulk delete comments
71
+ - Ability to schedule deletion of posts
72
+
73
+ ### Support
74
+
75
+ - If you have found a bug/issue or have a feature request, then post them in [github issues][7]
76
+ - If you have a question about usage or need help to troubleshoot, then post in WordPress forums or leave a comment in [Plugins's home page][1]
77
+ - If you like the Plugin, then kindly leave a review/feedback at [WordPress repo page][8].
78
+ - If you find this Plugin useful or and wanted to say thank you, then there are ways to [make me happy](http://sudarmuthu.com/if-you-wanna-thank-me) :) and I would really appreciate if you can do one of those.
79
+ - If anything else, then contact me in [twitter][3].
80
+
81
+ [1]: http://sudarmuthu.com/wordpress/bulk-delete
82
+ [2]: http://sudarmuthu.com/wordpress/bulk-move
83
+ [3]: http://twitter.com/sudarmuthu
84
+ [4]: http://sudarmuthu.com/blog
85
+ [5]: http://sudarmuthu.com/wordpress
86
+ [6]: https://github.com/sudar/bulk-delete
87
+ [7]: https://github.com/sudar/bulk-delete/issues
88
+ [8]: http://wordpress.org/extend/plugins/bulk-delete/
89
+
90
+ == Translation ==
91
+
92
+ The Plugin currently has translations for the following languages.
93
 
94
+ * Dutch (Thanks Rene of [WordPress WPwebshop][14])
95
+ * Brazilian Portuguese (Thanks Marcelo of [Criacao de Sites em Ribeirao Preto][15])
96
+ * German (Thanks Jenny Beelens of [professionaltranslation.com][16])
97
+ * Turkish Portuguese (Thanks [Bahadir Yildiz][17])
98
  * Spanish (Thanks Brian Flores of [InMotion Hosting][10])
99
  * Italian (Thanks Paolo Gabrielli)
100
  * Bulgarian (Thanks Nikolay Nikolov of [Skype Fan Blog][11])
103
  * Hindi (Thanks Love Chandel)
104
  * Serbian (Thanks Diana)
105
 
106
+ The pot file is available with the Plugin. If you are willing to do translation for the Plugin, use the pot file to create the .po files for your language and let me know. I will add it to the Plugin after giving credit to you.
 
 
 
 
107
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  [10]: http://www.inmotionhosting.com/
109
  [11]: http://en.chat4o.com/
110
  [12]: http://www.weblancer.net/users/Kirky/
111
  [13]: http://www.host1free.com
112
+ [14]: http://wpwebshop.com/premium-wordpress-plugins/
113
+ [15]: http://www.techload.com.br/
114
+ [16]: http://www.professionaltranslation.com
115
+ [17]: http://www.matematik.us
116
+
117
+ == Credits ==
118
+
119
+ Thanks <a href="http://www.martincapodici.com">Martin Capodici</a> for providing the code to implement the "delete specific page" feature.
120
+
121
+ Thanks to [Time picker addon](http://trentrichardson.com/examples/timepicker/) JavaScript library, which the Plugin uses.
122
 
123
  == Installation ==
124
 
132
 
133
  In particular try to change the following settings
134
 
135
+ * `max_execution_time = 600` - Maximum execution time of each script, in seconds
136
+ * `max_input_time = 30` - Maximum amount of time each script may spend parsing request data
137
+ * `memory_limit = 256M` - Maximum amount of memory a script may consume
138
 
139
+ = How do I know what are the current values for these options configured in my server? =
140
 
141
+ Scroll down to the button of the Plugin page and you can see the current values of these options printed for your reference under the “Debug Information” heading
142
 
143
+ = Is it possible to restore the posts that I have deleted through the Plugin? =
144
 
145
+ If you choose the option "Move to trash" then you can find them from trash. But if you choose "Delete permanently", then it is not possible to retrieve the posts. So be **very careful**.
146
 
147
+ = Is it possible to schedule deletion of posts =
148
 
149
+ The ability to schedule deletion of posts is available as a pro addon.
150
 
151
+ == Screenshots ==
152
 
153
+ 1. The above screenshot shows how you can delete Posts by type. You can choose between drafts, revisions, Pending posts, scheduled posts, privates posts, pages etc..
154
 
155
+ 2. The above screenshot shows how you can delete posts by tag
156
 
157
+ 3. The above screenshot shows how you can delete posts by Custom taxonomies
158
 
159
+ == Changelog ==
160
 
161
+ = 2013-04-27 - v3.0 - (Dev time: 10 hours) =
162
+ * Added support for pro addons
163
+ * Added GUI to see cron jobs
164
 
165
+ = v2.2.2 (2012-12-20) (Dev time: 0.5 hour) =
166
+ * Removed unused wpdb->prepare() function calls
167
 
168
+ = v2.2.1 (2012-10-28) (Dev time: 0.5 hour) =
169
+ * Added Serbian translations
170
 
171
+ = v2.2 (2012-07-11) (Dev time: 0.5 hour) =
172
+ * Added Hindi translations
173
+ * Added checks to see if elements are present in the array before accessing them.
174
 
175
+ = v2.1 (2012-04-07) Dev Time: 1 hour =
176
+ * Fixed CSS issues in IE
177
+ * Added Lithuanian translations
178
 
179
+ = v2.0 (2012-04-01) Dev Time: 10 hours =
180
+ * Fixed a major issue in how dates were handled.
181
+ * Major UI revamp
182
+ * Added debug information and support urls
183
 
184
+ = v1.9 (2012-03-16) =
185
+ * Added support for deleting by permalink. Credit Martin Capodici
186
+ * Fixed issues with translations
187
+ * Added Russian translations
188
 
189
+ = v1.8 (2012-01-31) =
190
+ * Added roles and capabilities for menu
191
 
192
+ = v1.7 (2012-01-12) =
193
+ * Added Bulgarian translations
194
 
195
+ = v1.6 (2011-11-28) =
196
+ * Added Italian translations
 
 
197
 
198
+ = v1.5 (2011-11-13) =
199
+ * Added Spanish translations
200
+
201
+ = v1.4 (2011-08-25) =
202
+ * Added Turkish translations
203
 
204
+ = v1.3 (2011-05-11) =
205
  * Added German translations
206
 
207
+ = v1.2 (2011-02-06) =
208
+ * Added some optimization to handle huge number of posts in underpowered servers
209
 
210
+ = v1.1 (2011-01-22) =
211
+ * Added support to delete posts by custom taxonomies
212
+ * Added Dutch Translation
213
+ * Added Brazilian Portuguese Translation
214
 
215
+ = v1.0 (2010-06-19) =
216
+ * Proper handling of limits.
217
 
218
+ = v0.8 (2010-03-17) =
219
+ * Added support for private posts.
220
 
221
+ = v0.7 (2010-02-21) =
222
+ * Added an option to delete posts directly or send them to trash.
223
+ * Added support for translation.
224
 
225
+ = v0.6 (2009-07-22) =
226
+ * Added option to delete all scheduled posts.
 
 
227
 
228
+ = v0.5 (2009-07-21) =
229
+ * Added option to delete all pending posts.
 
 
230
 
231
+ = v0.4 (2009-07-05) =
232
+ * Added option to delete by date.
 
233
 
234
+ = v0.3 (2009-04-05) =
235
+ * Prevented drafts from deleted when only posts are selected
 
236
 
237
+ = v0.2 (2009-02-03) =
238
+ * Fixed issues with paging
239
 
240
+ = v0.1 (2009-02-02) =
241
+ * First version
242
 
243
+ == Readme Generator ==
244
 
245
  This Readme file was generated using <a href = 'http://sudarmuthu.com/wordpress/wp-readme'>wp-readme</a>, which generates readme files for WordPress Plugins.
screenshot-1.png DELETED
Binary file
screenshot-2.png DELETED
Binary file
screenshot-3.png DELETED
Binary file
screenshot-4.png DELETED
Binary file
style/jquery-ui-timepicker.css ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ .ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }
2
+ .ui-timepicker-div dl { text-align: left; }
3
+ .ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; }
4
+ .ui-timepicker-div dl dd { margin: 0 10px 10px 65px; }
5
+ .ui-timepicker-div td { font-size: 90%; }
6
+ .ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; }
7
+
8
+ .ui-timepicker-rtl{ direction: rtl; }
9
+ .ui-timepicker-rtl dl { text-align: right; }
10
+ .ui-timepicker-rtl dl dd { margin: 0 65px 10px 10px; }