From 21d4c85c00f1c5372a55554f7055a1edf9d4d7b8 Mon Sep 17 00:00:00 2001
From: Tony Volpe Semantic Personal Publishing Platform Welcome. WordPress is a very special project to me. Every developer and contributor adds something unique to the mix, and together we create something beautiful that I am proud to be a part of. Thousands of hours have gone into WordPress, and we are dedicated to making it better every day. Thank you for making it part of your world. — Matt Mullenweg WordPress can import from a number of systems. First you need to get WordPress installed and working as described above, before using our import tools. If you have any questions that are not addressed in this document, please take advantage of WordPress’ numerous online resources: WordPress has no multi-million dollar marketing campaign or celebrity sponsors, but we do have something even better—you. If you enjoy WordPress please consider telling a friend, setting it up for someone less knowledgeable than yourself, or writing the author of a media article that overlooks us. WordPress is the official continuation of b2/cafélog, which came from Michel V. The work has been continued by the WordPress developers. If you would like to support WordPress, please consider donating. WordPress is free software, and is released under the terms of the GPL (GNU General Public License) version 2 or (at your option) any later version. See license.txt.
+
+
+First Things First
+Installation: Famous 5-minute install
+
+
+
+wp-config.php file with your database connection details.
+
+
+ wp-config-sample.php with a text editor like WordPad or similar and fill in your database connection details.wp-config.php and upload it.wp-config.php file, and try again. If it fails again, please go to the WordPress support forums with as much data as you can gather.admin.Updating
+Using the Automatic Updater
+
+
+
+Updating Manually
+
+
+
+index.php.Migrating from other systems
+System Requirements
+
+
+Recommendations
+
+
+
+Online Resources
+
+
+
+Final Notes
+
+
+
+Share the Love
+License
+
+ +
+ Version %1$s addressed %2$s bug.', + 'Version %1$s addressed %2$s bugs.', + 4 + ), + '6.4.1', + '4' + ); + ?> + the release notes.' ), + sprintf( + /* translators: %s: WordPress version. */ + esc_url( __( 'https://wordpress.org/support/wordpress-version/version-%s/' ) ), + sanitize_title( '6.4.1' ) + ) + ); + ?> +
diff --git a/wp/wp-admin/includes/class-file-upload-upgrader.php b/wp/wp-admin/includes/class-file-upload-upgrader.php index 2b76e41e..e6256151 100644 --- a/wp/wp-admin/includes/class-file-upload-upgrader.php +++ b/wp/wp-admin/includes/class-file-upload-upgrader.php @@ -69,6 +69,30 @@ class File_Upload_Upgrader { wp_die( $file['error'] ); } + if ( 'pluginzip' === $form || 'themezip' === $form ) { + $archive_is_valid = false; + + /** This filter is documented in wp-admin/includes/file.php */ + if ( class_exists( 'ZipArchive', false ) && apply_filters( 'unzip_file_use_ziparchive', true ) ) { + $archive = new ZipArchive(); + $archive_is_valid = $archive->open( $file['file'], ZIPARCHIVE::CHECKCONS ); + + if ( true === $archive_is_valid ) { + $archive->close(); + } + } else { + require_once ABSPATH . 'wp-admin/includes/class-pclzip.php'; + + $archive = new PclZip( $file['file'] ); + $archive_is_valid = is_array( $archive->properties() ); + } + + if ( true !== $archive_is_valid ) { + wp_delete_file( $file['file'] ); + wp_die( __( 'Incompatible Archive.' ) ); + } + } + $this->filename = $_FILES[ $form ]['name']; $this->package = $file['file']; diff --git a/wp/wp-admin/includes/schema.php b/wp/wp-admin/includes/schema.php index d339af3b..20648d7d 100644 --- a/wp/wp-admin/includes/schema.php +++ b/wp/wp-admin/includes/schema.php @@ -599,14 +599,12 @@ function populate_options( array $options = array() ) { $autoload = 'yes'; } - if ( is_array( $value ) ) { - $value = serialize( $value ); - } - if ( ! empty( $insert ) ) { $insert .= ', '; } + $value = maybe_serialize( sanitize_option( $option, $value ) ); + $insert .= $wpdb->prepare( '(%s, %s, %s)', $option, $value, $autoload ); } diff --git a/wp/wp-admin/update.php b/wp/wp-admin/update.php index 29480c28..090c37cf 100644 --- a/wp/wp-admin/update.php +++ b/wp/wp-admin/update.php @@ -154,6 +154,10 @@ if ( isset( $_GET['action'] ) ) { check_admin_referer( 'plugin-upload' ); + if ( isset( $_FILES['pluginzip']['name'] ) && ! str_ends_with( strtolower( $_FILES['pluginzip']['name'] ), '.zip' ) ) { + wp_die( __( 'Only .zip archives may be uploaded.' ) ); + } + $file_upload = new File_Upload_Upgrader( 'pluginzip', 'package' ); // Used in the HTML title tag. @@ -302,6 +306,10 @@ if ( isset( $_GET['action'] ) ) { check_admin_referer( 'theme-upload' ); + if ( isset( $_FILES['themezip']['name'] ) && ! str_ends_with( strtolower( $_FILES['themezip']['name'] ), '.zip' ) ) { + wp_die( __( 'Only .zip archives may be uploaded.' ) ); + } + $file_upload = new File_Upload_Upgrader( 'themezip', 'package' ); // Used in the HTML title tag. diff --git a/wp/wp-config-sample.php b/wp/wp-config-sample.php new file mode 100644 index 00000000..feb1137f --- /dev/null +++ b/wp/wp-config-sample.php @@ -0,0 +1,96 @@ + 1) { - for (var x = 1; x < v.length; x++) { - var att = v[x].split('='); - if (att.length === 2) { - var key = att[0]; - atts[key] = att[1].split("'").join(''); - } - } - } - var value = ''; - switch (tag) { - case 'CF7_GET': - value = dtx.get(atts); - break; - case 'CF7_referrer': - value = dtx.referrer(atts); - break; - case 'CF7_URL': - value = dtx.current_url(atts); - break; - case 'CF7_get_cookie': - value = dtx.get_cookie(atts); - break; - case 'CF7_guid': - value = dtx.guid(); - break; - case 'CF7_get_current_var': - if (dtx.validKey(atts, 'key') && atts.key == 'url') { - value = dtx.current_url(atts); - } else { - return; // Do nothing, current page variables are safe to cache, just use the value that was calculated by server - } - break; - case 'CF7_get_post_var': // Current post variables are safe to cache - case 'CF7_get_custom_field': // Meta data is safe to cache - case 'CF7_get_taxonomy': // Terms are safe to cache - case 'CF7_get_attachment': // Media attachment info is safe to cache - case 'CF7_bloginfo': // Site info is safe to cache - case 'CF7_get_theme_option': // Theme options are safe to cache - return; // Do nothing, just use the value that was calculated by server - default: - if (tag) { - // Queue the requests for an AJAX call at the end of init - dtx.queue.push({ 'value': raw_value, 'multiline': $input.is('textarea') }); - } - return; // Don't continue after queuing it for AJAX - } - dtx.set($input, value); - } - }); - if (dtx.queue.length) { - setTimeout(function() { // Set timeout to force it async - $.ajax({ - type: 'POST', - url: dtx_obj.ajax_url, - dataType: 'json', // only accept strict JSON objects - data: { - 'action': 'wpcf7dtx', - 'shortcodes': dtx.queue - }, - cache: false, - error: function(xhr, status, error) { - console.error('[CF7 DTX AJAX ERROR]', error, status, xhr); - }, - success: function(data, status, xhr) { - if (typeof(data) == 'object' && data.length) { - $.each(data, function(i, obj) { - var $inputs = $('.wpcf7 form input.dtx-pageload[data-dtx-value="' + obj.raw_value + '"]'); - if ($inputs.length) { - dtx.set($inputs, obj.value); - $inputs.addClass('dtx-ajax-loaded'); - } - }); - } - } - }); - }, 10); - } - } - }, - /** - * Check if Key Exists in Object - */ - validKey: function(obj, key) { - return obj.hasOwnProperty(key) && typeof(obj[key]) == 'string' && obj[key].trim(); - }, - /** - * Maybe Obfuscate Value - * - * @see https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-attribute-obfuscate/ - */ - obfuscate: function(value, atts) { - value = value.trim(); - if (dtx.validKey(atts, 'obfuscate') && atts.obfuscate) { - var o = ''; - for (var i = 0; i < value.length; i++) { - o += '' + value.codePointAt(i) + ';'; - } - return o; - } - return value; - }, - /** - * Set Value for Form Field - */ - set: function($input, value) { - $input.attr('value', value).addClass('dtx-loaded'); - }, - /** - * Get Value form URL Query by Key - * - * @see @see https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-shortcode-php-get-variables/ - */ - get: function(atts) { - if (dtx.validKey(atts, 'key')) { - var query = window.location.search; - if (query) { - query = new URLSearchParams(query); - return dtx.obfuscate(query.get(atts.key).trim(), atts); - } - } - return ''; - }, - /** - * Get Referrering URL - * - * @see https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-shortcode-referrer-url/ - */ - referrer: function(atts) { - return dtx.obfuscate(document.referrer, atts); - }, - /** - * Get Current URL or Part - * - * @see https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-shortcode-current-url/ - */ - current_url: function(atts) { - if (atts.hasOwnProperty('part')) { - var parts = [ - 'scheme', // e.g. `http` - 'host', - 'port', - 'path', - 'query', // after the question mark ? - 'fragment' // after the pound sign # - ]; - if (parts.includes(atts.part)) { - // return part of the url - switch (atts.part) { - case 'scheme': - return dtx.obfuscate(window.location.protocol.replace(':', ''), atts); - case 'host': - return dtx.obfuscate(window.location.host, atts); - case 'port': - return dtx.obfuscate(window.location.port, atts); - case 'path': - return dtx.obfuscate(window.location.pathname, atts); - case 'query': - return dtx.obfuscate(window.location.search.replace('?', ''), atts); - case 'fragment': - return dtx.obfuscate(window.location.hash.replace('#', ''), atts); - default: - break; - } - } - } else { - return dtx.obfuscate(window.location.href, atts); // Return the full url - } - return ''; - }, - /** - * Get Cookie Value - * - * @since 3.3.0 - * - * @see https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-shortcode-cookie/ - */ - get_cookie: function(atts) { - if (atts.hasOwnProperty('key') && typeof(atts.key) == 'string' && atts.key.trim() != '') { - var keyValue = document.cookie.match('(^|;) ?' + atts.key.trim() + '=([^;]*)(;|$)'); - return keyValue ? dtx.obfuscate(keyValue[2], atts) : ''; - } - return ''; - }, - /** - * Generate a random GUID (globally unique identifier) - * - * @see https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-shortcode-guid/ - */ - guid: function() { - if (typeof(window.crypto) != 'undefined' && typeof(window.crypto.getRandomValues) != 'undefined') { - return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => - (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) - ).toUpperCase(); - } - console.warn('[CF7 DTX] Cryptographically secure PRNG is not available for generating GUID value'); - var d = new Date().getTime(), //Timestamp - d2 = ((typeof performance !== 'undefined') && performance.now && (performance.now() * 1000)) || 0; //Time in microseconds since page-load or 0 if unsupported - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random() * 16; //random number between 0 and 16 - if (d > 0) { //Use timestamp until depleted - r = (d + r) % 16 | 0; - d = Math.floor(d / 16); - } else { //Use microseconds since page-load if supported - r = (d2 + r) % 16 | 0; - d2 = Math.floor(d2 / 16); - } - return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16).toUpperCase(); - }).toUpperCase();; - } - }; +window['$'] = window['$'] || jQuery.noConflict(); +var dtx = { + queue: [], + init: function() { + var $inputs = $('input.dtx-pageload[data-dtx-value]'); + if ($inputs.length) { + // If this is any of our built-in shortcodes, see if there's any that can be duplicated via client side + $inputs.each(function(i, el) { + var $input = $(el), + raw_value = $input.attr('data-dtx-value'), + v = decodeURIComponent(raw_value).split(' '); + if (v.length) { + var tag = v[0], + atts = {}; + if (v.length > 1) { + for (var x = 1; x < v.length; x++) { + var att = v[x].split('='); + if (att.length === 2) { + var key = att[0]; + atts[key] = att[1].split("'").join(''); + } + } + } + var value = ''; + switch (tag) { + case 'CF7_GET': + value = dtx.get(atts); + break; + case 'CF7_referrer': + value = dtx.referrer(atts); + break; + case 'CF7_URL': + value = dtx.current_url(atts); + break; + case 'CF7_get_cookie': + value = dtx.get_cookie(atts); + break; + case 'CF7_guid': + value = dtx.guid(); + break; + case 'CF7_get_current_var': + if (dtx.validKey(atts, 'key') && atts.key == 'url') { + value = dtx.current_url(atts); + } else { + return; // Do nothing, current page variables are safe to cache, just use the value that was calculated by server + } + break; + case 'CF7_get_post_var': // Current post variables are safe to cache + case 'CF7_get_custom_field': // Meta data is safe to cache + case 'CF7_get_taxonomy': // Terms are safe to cache + case 'CF7_get_attachment': // Media attachment info is safe to cache + case 'CF7_bloginfo': // Site info is safe to cache + case 'CF7_get_theme_option': // Theme options are safe to cache + return; // Do nothing, just use the value that was calculated by server + default: + if (tag) { + // Queue the requests for an AJAX call at the end of init + dtx.queue.push({ 'value': raw_value, 'multiline': $input.is('textarea') }); + } + return; // Don't continue after queuing it for AJAX + } + dtx.set($input, value); + } + }); + if (dtx.queue.length) { + setTimeout(function() { // Set timeout to force it async + $.ajax({ + type: 'POST', + url: dtx_obj.ajax_url, + dataType: 'json', // only accept strict JSON objects + data: { + 'action': 'wpcf7dtx', + 'shortcodes': dtx.queue + }, + cache: false, + error: function(xhr, status, error) { + console.error('[CF7 DTX AJAX ERROR]', error, status, xhr); + }, + success: function(data, status, xhr) { + if (typeof(data) == 'object' && data.length) { + $.each(data, function(i, obj) { + var $inputs = $('.wpcf7 form input.dtx-pageload[data-dtx-value="' + obj.raw_value + '"]'); + if ($inputs.length) { + $inputs.addClass('dtx-ajax-loaded'); + dtx.set($inputs, obj.value); + } + }); + } + } + }); + }, 10); + } + } + }, + /** + * Check if Key Exists in Object + */ + validKey: function(obj, key) { + return obj.hasOwnProperty(key) && typeof(obj[key]) == 'string' && obj[key].trim(); + }, + /** + * Maybe Obfuscate Value + * + * @see https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-attribute-obfuscate/ + */ + obfuscate: function(value, atts) { + value = value.trim(); + if (dtx.validKey(atts, 'obfuscate') && atts.obfuscate) { + var o = ''; + for (var i = 0; i < value.length; i++) { + o += '' + value.codePointAt(i) + ';'; + } + return o; + } + return value; + }, + /** + * Set Value for Form Field + */ + set: function($input, value) { + $input + .attr('value', value) + .addClass('dtx-loaded') + .trigger('dtx_init'); + }, + /** + * Get Value form URL Query by Key + * + * @see @see https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-shortcode-php-get-variables/ + */ + get: function(atts) { + if (dtx.validKey(atts, 'key')) { + var query = window.location.search; + if (query) { + query = new URLSearchParams(query); + return dtx.obfuscate(query.get(atts.key).trim(), atts); + } + } + return ''; + }, + /** + * Get Referrering URL + * + * @see https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-shortcode-referrer-url/ + */ + referrer: function(atts) { + return dtx.obfuscate(document.referrer, atts); + }, + /** + * Get Current URL or Part + * + * @see https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-shortcode-current-url/ + */ + current_url: function(atts) { + if (atts.hasOwnProperty('part')) { + var parts = [ + 'scheme', // e.g. `http` + 'host', + 'port', + 'path', + 'query', // after the question mark ? + 'fragment' // after the pound sign # + ]; + if (parts.includes(atts.part)) { + // return part of the url + switch (atts.part) { + case 'scheme': + return dtx.obfuscate(window.location.protocol.replace(':', ''), atts); + case 'host': + return dtx.obfuscate(window.location.host, atts); + case 'port': + return dtx.obfuscate(window.location.port, atts); + case 'path': + return dtx.obfuscate(window.location.pathname, atts); + case 'query': + return dtx.obfuscate(window.location.search.replace('?', ''), atts); + case 'fragment': + return dtx.obfuscate(window.location.hash.replace('#', ''), atts); + default: + break; + } + } + } else { + return dtx.obfuscate(window.location.href, atts); // Return the full url + } + return ''; + }, + /** + * Get Cookie Value + * + * @since 3.3.0 + * + * @see https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-shortcode-cookie/ + */ + get_cookie: function(atts) { + if (atts.hasOwnProperty('key') && typeof(atts.key) == 'string' && atts.key.trim() != '') { + var keyValue = document.cookie.match('(^|;) ?' + atts.key.trim() + '=([^;]*)(;|$)'); + return keyValue ? dtx.obfuscate(keyValue[2], atts) : ''; + } + return ''; + }, + /** + * Generate a random GUID (globally unique identifier) + * + * @see https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/shortcodes/dtx-shortcode-guid/ + */ + guid: function() { + if (typeof(window.crypto) != 'undefined' && typeof(window.crypto.getRandomValues) != 'undefined') { + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => + (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) + ).toUpperCase(); + } + console.warn('[CF7 DTX] Cryptographically secure PRNG is not available for generating GUID value'); + var d = new Date().getTime(), //Timestamp + d2 = ((typeof performance !== 'undefined') && performance.now && (performance.now() * 1000)) || 0; //Time in microseconds since page-load or 0 if unsupported + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = Math.random() * 16; //random number between 0 and 16 + if (d > 0) { //Use timestamp until depleted + r = (d + r) % 16 | 0; + d = Math.floor(d / 16); + } else { //Use microseconds since page-load if supported + r = (d2 + r) % 16 | 0; + d2 = Math.floor(d2 / 16); + } + return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16).toUpperCase(); + }).toUpperCase();; + } +}; $(document).ready(dtx.init); \ No newline at end of file diff --git a/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/assets/scripts/dtx.min.js b/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/assets/scripts/dtx.min.js index a361301f..ea085bca 100644 --- a/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/assets/scripts/dtx.min.js +++ b/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/assets/scripts/dtx.min.js @@ -1,2 +1,2 @@ -/*! Do not edit, this file is generated automatically - 2024-01-09 15:01:30 MST */ -var $=jQuery.noConflict(),dtx={queue:[],init:function(){var e=$("input.dtx-pageload[data-dtx-value]");e.length&&(e.each(function(e,t){var r=$(t),a=r.attr("data-dtx-value"),o=decodeURIComponent(a).split(" ");if(o.length){var n=o[0],c={};if(1%s %s
render_back_to_settings_button(); ?>
-- -
- - - > -- -
- - -- -
- - -- -
- - -- -
- 'cf7dtx_settings[' . $field['id'] . ']', - 'textarea_rows' => 5, - ) - ); - break; - } - - case "email": { - ?> - -- -
- - -- -
- - -- -
- - -- -
- -sections[$args['id']]['description']; ?>
-'.__('Scan complete. No keys detected.', 'contact-form-7-dynamic-text-extension').'
'; - $this->render_back_to_settings_button(); - return; - } - - // Check if we need to scan another batch - if( $results['forms_scanned'] === $this->num_forms_to_scan ){ - $offset = isset( $_GET['offset'] ) ? $_GET['offset'] : 0; - $next_offset = $offset + $this->num_forms_to_scan; - echo ''; - echo sprintf( - __( '%1$s forms scanned. There may be more forms to scan.', 'contact-form-7-dynamic-text-extension' ), - $results['forms_scanned'], - ); - echo ' '; - echo ''.sprintf( - __( 'Scan %1$s more forms', 'contact-form-7-dynamic-text-extension' ), - $this->num_forms_to_scan - ).''; - echo '
:
- - -:
- - - - - - - render_back_to_settings_button(); - } - - function render_back_to_settings_button(){ - ?> - « - [ - 'title' => __('Post Meta Access', 'contact-form-7-dynamic-text-extension'), - 'description' => __('Control which post metadata the CF7 DTX shortcodes (CF7_get_custom_field) can access. By default, all metadata is protected, so you can open up access through these settings. Keep in mind that users with Contributor+ credentials can add shortcodes and therefore access this data, so make sure not to expose anything sensitive.'). - ' '. __('More Information', 'contact-form-7-dynamic-text-extension' ).'', - ], - 'user_data_access' => [ - 'title' => __('User Data Access', 'contact-form-7-dynamic-text-extension'), - 'description' => __('Control which user data the CF7 DTX shortcodes (CF7_get_current_user) can access. By default, all user data is protected, so you can open up access through these settings. Keep in mind that users with Contributor+ credentials can add shortcodes and therefore access this data, so make sure not to expose anything sensitive.'). - ' '. __('More Information', 'contact-form-7-dynamic-text-extension' ).'', - ], -]; - -/** - * Array of fields that should be displayed in the settings page. - * - * @var array $fields - */ -$fields = [ - [ - 'id' => 'post_meta_allow_keys', - 'label' => __('Meta Key Allow List', 'contact-form-7-dynamic-text-extension'), - 'description' => __('Allow access to these specific post metadata keys. Enter one per line.', 'contact-form-7-dynamic-text-extension'), - 'type' => 'textarea', - 'section' => 'post_meta_access', - ], - [ - 'id' => 'post_meta_allow_all', - 'label' => __('Allow Access to All Post Metadata', 'contact-form-7-dynamic-text-extension'), - 'description' => __('**Use with caution.** Should only be enabled if all authorized users with editor privileges (Contributor+) are trusted and should have access to this data. All metadata from any post (including custom post types) will be accessible via the CF7_get_custom_field shortcode. If in doubt, use the Allow List to allow only specific keys.', 'contact-form-7-dynamic-text-extension'), - 'type' => 'select', - 'options' => [ - 'disabled' => __( 'Disabled - Only Allow Access to Meta Key Allow List', 'contact-form-7-dynamic-text-extension' ), - 'enabled' => __( 'Enabled - Allow Access to All Post Metadata', 'contact-form-7-dynamic-text-extension' ), - ], - 'section' => 'post_meta_access', - ], - [ - 'id' => 'user_data_allow_keys', - 'label' => __('User Data Key Allow List', 'contact-form-7-dynamic-text-extension'), - 'description' => __('Allow access to these specific user data keys. Enter one per line.', 'contact-form-7-dynamic-text-extension'), - 'type' => 'textarea', - 'section' => 'user_data_access', - ], - [ - 'id' => 'user_data_allow_all', - 'label' => __('Allow Access to All User Data', 'contact-form-7-dynamic-text-extension'), - 'description' => __('**Use with caution.** Should only be enabled if all authorized users with editor privileges (Contributor+) are trusted and should have access to this data. All of the current user\'s data fields will be accessible via the CF7_get_current_user shortcode. If in doubt, use the Allow List to allow only specific keys.', 'contact-form-7-dynamic-text-extension'), - 'type' => 'select', - 'options' => [ - 'disabled' => __( 'Disabled - Only Allow Access to User Data Key Allow List', 'contact-form-7-dynamic-text-extension' ), - 'enabled' => __( 'Enabled - Allow Access to User Data', 'contact-form-7-dynamic-text-extension' ), - ], - 'section' => 'user_data_access', - ], -]; - - -new CF7DTX_Plugin_Settings($sections, $fields); - - -function wpcf7dtx_get_admin_scan_screen_url($offset=0){ - $path = 'admin.php?page=cf7dtx_settings&scan-meta-keys'; - if( $offset ){ - $path.= '&offset='.$offset; - } - return admin_url($path); -} -function wpcf7dtx_get_admin_settings_screen_url(){ - return admin_url('admin.php?page=cf7dtx_settings'); -} - - -/** - * Search all CF7 forms for - */ -function wpcf7dtx_scan_forms_for_access_keys( $num, $offset=0){ - - $found = [ - 'forms' => [], - ]; - $forms = []; - - if( function_exists('wpcf7_contact_form') ){ - - $cf7forms = get_posts([ - 'post_type' => 'wpcf7_contact_form', - // 'numberposts' => $numposts, // sanity check - 'posts_per_page' => $num, - 'offset' => $offset, - ]); - - $found['forms_scanned'] = count($cf7forms); - - // Loop through forms - foreach( $cf7forms as $form ){ - - // Search for the custom fields shortcode - if( str_contains($form->post_content, 'CF7_get_custom_field') || - str_contains($form->post_content, 'CF7_get_current_user') - ){ - $cf7 = wpcf7_contact_form( $form->ID ); - - $forms[$form->ID] = [ - 'title' => $cf7->title(), - 'meta_keys' => [], - 'user_keys' => [], - 'admin_url' => admin_url( "admin.php?page=wpcf7&post={$form->ID}&action=edit" ), - ]; - - $tags = $cf7->scan_form_tags(); - - // Check each tag - foreach( $tags as $tag ){ - // Find dynamic tags - if( str_starts_with( $tag->type, 'dynamic' ) ){ - // Check each value - foreach( $tag->values as $val ){ - // Find CF7_get_custom_field - if( str_starts_with( $val, 'CF7_get_custom_field' )){ - // Parse out the shortcode atts - $atts = shortcode_parse_atts($val); - if( $atts ){ - // Grab the meta key - $meta_key = $atts['key']; - - // Add meta key to the list - if( $meta_key ){ - $forms[$form->ID]['meta_keys'][] = $meta_key; - } - } - } - // Find CF7_get_current_user - if( str_starts_with( $val, 'CF7_get_current_user' )){ - // Parse out the shortcode atts - $atts = shortcode_parse_atts($val); - if( $atts ){ - // Grab user data key - $key = $atts['key']; - if( $key ){ - $forms[$form->ID]['user_keys'][] = $key; - } - } - } - } - } - } - } - } - } - $found['forms'] = $forms; - return $found; - -} +sections = $sections; + $this->fields = $fields; + } + + /** + * Register the settings and all fields. + * + * @since 4.2.0 + * + * @return void + */ + function settings_init(): void + { + + // Register a new setting this page. + register_setting('cf7dtx_settings', 'cf7dtx_settings'); + + foreach ($this->sections as $section_id => $section) { + // Register a new section. + add_settings_section( + $section_id, + $section['title'], + [$this, 'render_section'], + 'cf7dtx_settings', + ); + } + + + /* Register All The Fields. */ + foreach ($this->fields as $field) { + // Register a new field in the main section. + add_settings_field( + $field['id'], /* ID for the field. Only used internally. To set the HTML ID attribute, use $args['label_for']. */ + $field['label'], /* Label for the field. */ + [$this, 'render_field'], /* The name of the callback function. */ + 'cf7dtx_settings', /* The menu page on which to display this field. */ + $field['section'], /* The section of the settings page in which to show the box. */ + [ + 'label_for' => $field['id'], /* The ID of the field. */ + 'class' => 'cf7dtx_row', /* The class of the field. */ + 'field' => $field, /* Custom data for the field. */ + ] + ); + } + } + + /** + * Add a subpage to the WordPress Settings menu. + * + * @since 4.2.0 + * + * @return void + */ + function options_page(): void + { + add_submenu_page( + 'wpcf7', /* Parent Menu Slug */ + 'Contact Form 7 - Dynamic Text Extension', /* Page Title */ + 'Dynamic Text Extension', /* Menu Title */ + $this->capability, /* Capability */ + 'cf7dtx_settings', /* Menu Slug */ + [$this, 'render_options_page'], /* Callback */ + ); + } + + /** + * Render the settings page. + * + * @since 4.2.0 + * + * @return void + */ + function render_options_page(): void + { + + // check user capabilities + if (!current_user_can($this->capability)) { + return; + } + + if (isset($_GET['dismiss-access-keys-notice'])) { + wpcf7dtx_set_update_access_scan_check_status('notice_dismissed'); +?> +render_back_to_settings_button(); ?>
++ +
+ + > ++ +
+ + ++ +
+ + ++ +
+ + ++ +
+ 'cf7dtx_settings[' . $field['id'] . ']', + 'textarea_rows' => 5, + ) + ); + break; + } + + case "email": { + ?> + ++ +
+ + ++ +
+ + ++ +
+ + ++ +
+ +sections[$args['id']]['description']; ?>
+' . __('Scan complete. No keys detected.', 'contact-form-7-dynamic-text-extension') . '
'; + $this->render_back_to_settings_button(); + return; + } + + // Check if we need to scan another batch + if ($results['forms_scanned'] === $this->num_forms_to_scan) { + $offset = isset($_GET['offset']) ? $_GET['offset'] : 0; + $next_offset = $offset + $this->num_forms_to_scan; + echo ''; + echo sprintf( + __('%1$s forms scanned. There may be more forms to scan.', 'contact-form-7-dynamic-text-extension'), + $results['forms_scanned'], + ); + echo ' '; + echo '' . sprintf( + __('Scan %1$s more forms', 'contact-form-7-dynamic-text-extension'), + $this->num_forms_to_scan + ) . ''; + echo '
:
+ + +:
+ + + + + + + render_back_to_settings_button(); + } + + /** + * Render Back to Settings Button + * + * @since 4.2.0 + * + * @return void + */ + function render_back_to_settings_button() + { + ?> + « + [ + 'title' => __('Post Meta Access', 'contact-form-7-dynamic-text-extension'), + 'description' => __('Control which post metadata the CF7 DTX shortcodes (CF7_get_custom_field) can access. By default, all metadata is protected, so you can open up access through these settings. Keep in mind that users with Contributor+ credentials can add shortcodes and therefore access this data, so make sure not to expose anything sensitive.') . + ' ' . __('More Information', 'contact-form-7-dynamic-text-extension') . '', + ], + 'user_data_access' => [ + 'title' => __('User Data Access', 'contact-form-7-dynamic-text-extension'), + 'description' => __('Control which user data the CF7 DTX shortcodes (CF7_get_current_user) can access. By default, all user data is protected, so you can open up access through these settings. Keep in mind that users with Contributor+ credentials can add shortcodes and therefore access this data, so make sure not to expose anything sensitive.') . + ' ' . __('More Information', 'contact-form-7-dynamic-text-extension') . '', + ], +]; + +/** + * Array of fields that should be displayed in the settings page. + * + * @var array $fields + */ +$fields = [ + [ + 'id' => 'post_meta_allow_keys', + 'label' => __('Meta Key Allow List', 'contact-form-7-dynamic-text-extension'), + 'description' => __('Allow access to these specific post metadata keys. Enter one per line.', 'contact-form-7-dynamic-text-extension'), + 'type' => 'textarea', + 'section' => 'post_meta_access', + ], + [ + 'id' => 'post_meta_allow_all', + 'label' => __('Allow Access to All Post Metadata', 'contact-form-7-dynamic-text-extension'), + 'description' => __('**Use with caution.** Should only be enabled if all authorized users with editor privileges (Contributor+) are trusted and should have access to this data. All metadata from any post (including custom post types) will be accessible via the CF7_get_custom_field shortcode. If in doubt, use the Allow List to allow only specific keys.', 'contact-form-7-dynamic-text-extension'), + 'type' => 'select', + 'options' => [ + 'disabled' => __('Disabled - Only Allow Access to Meta Key Allow List', 'contact-form-7-dynamic-text-extension'), + 'enabled' => __('Enabled - Allow Access to All Post Metadata', 'contact-form-7-dynamic-text-extension'), + ], + 'section' => 'post_meta_access', + ], + [ + 'id' => 'user_data_allow_keys', + 'label' => __('User Data Key Allow List', 'contact-form-7-dynamic-text-extension'), + 'description' => __('Allow access to these specific user data keys. Enter one per line.', 'contact-form-7-dynamic-text-extension'), + 'type' => 'textarea', + 'section' => 'user_data_access', + ], + [ + 'id' => 'user_data_allow_all', + 'label' => __('Allow Access to All User Data', 'contact-form-7-dynamic-text-extension'), + 'description' => __('**Use with caution.** Should only be enabled if all authorized users with editor privileges (Contributor+) are trusted and should have access to this data. All of the current user\'s data fields will be accessible via the CF7_get_current_user shortcode. If in doubt, use the Allow List to allow only specific keys.', 'contact-form-7-dynamic-text-extension'), + 'type' => 'select', + 'options' => [ + 'disabled' => __('Disabled - Only Allow Access to User Data Key Allow List', 'contact-form-7-dynamic-text-extension'), + 'enabled' => __('Enabled - Allow Access to User Data', 'contact-form-7-dynamic-text-extension'), + ], + 'section' => 'user_data_access', + ], +]; + + +new CF7DTX_Plugin_Settings($sections, $fields); + + +function wpcf7dtx_get_admin_scan_screen_url($offset = 0) +{ + $path = 'admin.php?page=cf7dtx_settings&scan-meta-keys'; + if ($offset) { + $path .= '&offset=' . $offset; + } + return admin_url($path); +} +function wpcf7dtx_get_admin_settings_screen_url() +{ + return admin_url('admin.php?page=cf7dtx_settings'); +} + + +/** + * Search all CF7 forms for + */ +function wpcf7dtx_scan_forms_for_access_keys($num, $offset = 0) +{ + + $found = [ + 'forms' => [], + ]; + $forms = []; + + if (function_exists('wpcf7_contact_form')) { + + $cf7forms = get_posts([ + 'post_type' => 'wpcf7_contact_form', + // 'numberposts' => $numposts, // sanity check + 'posts_per_page' => $num, + 'offset' => $offset, + ]); + + $found['forms_scanned'] = count($cf7forms); + + // Loop through forms + foreach ($cf7forms as $form) { + + // Search for the custom fields shortcode + if ( + strpos($form->post_content, 'CF7_get_custom_field') !== false || + strpos($form->post_content, 'CF7_get_current_user') !== false + ) { + $cf7 = wpcf7_contact_form($form->ID); + + $forms[$form->ID] = [ + 'title' => $cf7->title(), + 'meta_keys' => [], + 'user_keys' => [], + 'admin_url' => admin_url("admin.php?page=wpcf7&post={$form->ID}&action=edit"), + ]; + + $tags = $cf7->scan_form_tags(); + + // Check each tag + foreach ($tags as $tag) { + // Find dynamic tags + if (str_starts_with($tag->type, 'dynamic')) { + // Check each value + foreach ($tag->values as $val) { + // Find CF7_get_custom_field + if (str_starts_with($val, 'CF7_get_custom_field')) { + // Parse out the shortcode atts + $atts = shortcode_parse_atts($val); + if ($atts) { + // Grab the meta key + $meta_key = $atts['key']; + + // Add meta key to the list + if ($meta_key) { + $forms[$form->ID]['meta_keys'][] = $meta_key; + } + } + } + // Find CF7_get_current_user + if (str_starts_with($val, 'CF7_get_current_user')) { + // Parse out the shortcode atts + $atts = shortcode_parse_atts($val); + if ($atts) { + // Grab user data key + $key = $atts['key']; + if ($key) { + $forms[$form->ID]['user_keys'][] = $key; + } + } + } + } + } + } + } + } + } + $found['forms'] = $forms; + return $found; +} diff --git a/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/includes/admin/update-check.php b/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/includes/admin/update-check.php index adc56c69..0c7169ef 100644 --- a/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/includes/admin/update-check.php +++ b/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/includes/admin/update-check.php @@ -1,97 +1,140 @@ -roles ) ) return; - - // If the status doesn't require intervention, don't do anything - $status = get_option( 'cf7dtx_v4_2_0_access_scan_check_status', '' ); - if( $status !== 'intervention_required' ){ - return; - } - ?> - - roles)) return; + + // If the status doesn't require intervention, don't do anything + $status = get_option('cf7dtx_v4_2_0_access_scan_check_status', ''); + if ($status !== 'intervention_required') { + return; + } +?> + + array(), 'name' => array(), 'value' => array(), - 'required' => array(), 'class' => array(), 'disabled' => array(), - 'readonly' => array(), 'tabindex' => array(), - 'size' => array(), 'title' => array(), - 'autofocus' => array(), // ARIA properties 'aria-invalid' => array(), 'aria-describedby' => array(), // DTX properties 'data-dtx-value' => array(), ); + if ($type != 'hidden') { + $allowed_properties['autofocus'] = array(); + $allowed_properties['readonly'] = array(); + $allowed_properties['required'] = array(); + } if (in_array($type, array('checkbox', 'radio', 'acceptance'))) { // Properties exclusive to checkboxes and radio buttons $allowed_properties['checked'] = array(); $allowed_properties['dtx-default'] = array(); - } elseif (in_array($type, array('number', 'range'))) { - // Properties exclusive to number inputs - $allowed_properties['step'] = array(); } elseif ($type == 'select') { // Properties exclusive to select fields + $allowed_properties['size'] = array(); $allowed_properties['multiple'] = array(); $allowed_properties['dtx-default'] = array(); - unset($allowed_properties['type'], $allowed_properties['value'], $allowed_properties['placeholder'], $allowed_properties['size']); // Remove invalid select attributes - } - if (!in_array($type, array('checkbox', 'radio', 'select', 'acceptance'))) { - // Allowed properties for all text-based inputs - $allowed_properties['placeholder'] = array(); + unset($allowed_properties['type'], $allowed_properties['value']); // Remove invalid select attributes + } else { + // Properties exclusive to text-based inputs $allowed_properties['autocomplete'] = array(); - $allowed_properties['minlength'] = array(); - $allowed_properties['maxlength'] = array(); - if (in_array($type, array('number', 'range', 'date', 'datetime-local', 'time'))) { - // Additional properties for number and date inputs - $allowed_properties['min'] = array(); - $allowed_properties['max'] = array(); + $allowed_properties['list'] = array(); + + // Placeholder + if (in_array($type, array('text', 'search', 'url', 'tel', 'email', 'password', 'number'))) { + $allowed_properties['placeholder'] = array(); } + + // Textarea if ($type == 'textarea') { // Additional properties exclusive to textarea fields $allowed_properties['cols'] = array(); $allowed_properties['rows'] = array(); + $allowed_properties['minlength'] = array(); + $allowed_properties['maxlength'] = array(); + $allowed_properties['wrap'] = array(); unset($allowed_properties['type'], $allowed_properties['value']); // Remove invalid textarea attributes - } elseif (in_array($type, array('text', 'date', 'url', 'tel', 'email', 'password'))) { - // Additional properties exclusive to specific text fields + } elseif (in_array($type, array('text', 'search', 'url', 'tel', 'email', 'password'))) { + // Additional properties exclusive to these text-based fields + $allowed_properties['size'] = array(); + $allowed_properties['minlength'] = array(); + $allowed_properties['maxlength'] = array(); $allowed_properties['pattern'] = array(); + } elseif (in_array($type, array('number', 'range', 'date', 'datetime-local', 'time'))) { + // Number and date inputs + $allowed_properties['min'] = array(); + $allowed_properties['max'] = array(); + $allowed_properties['step'] = array(); } } if (is_array($extra) && count($extra)) { @@ -554,8 +569,10 @@ function wpcf7dtx_textarea_html($atts) * group's options. It also accepts a string value of HTML already formatted as options or * option groups. It also accepts a string value of a self-closing shortcode that is * evaluated and its output is either options or option groups. - * @param bool $hide_blank Optional. If true, the first blank placeholder option will have the `hidden` attribute added to it. Default is false. - * @param bool $disable_blank Optional. If true, the first blank placeholder option will have the `disabled` attribute added to it. Default is false. + * @param bool $hide_blank Optional. If true, the first blank placeholder option will have the + * `hidden` attribute added to it. Default is false. + * @param bool $disable_blank Optional. If true, the first blank placeholder option will have + * the `disabled` attribute added to it. Default is false. * * @return string HTML output of select field */ @@ -644,9 +661,11 @@ function wpcf7dtx_select_html($atts, $options, $hide_blank = false, $disable_bla * * @param string|int $key The key to search for in the array. * @param array $array The array to search. - * @param mixed $default The default value to return if not found or is empty. Default is an empty string. + * @param mixed $default The default value to return if not found or is empty. Default is + * an empty string. * - * @return mixed The value of the key found in the array if it exists or the value of `$default` if not found or is empty. + * @return mixed The value of the key found in the array if it exists or the value of + * `$default` if not found or is empty. */ function wpcf7dtx_array_has_key($key, $array = array(), $default = '') { @@ -665,163 +684,163 @@ function wpcf7dtx_array_has_key($key, $array = array(), $default = '') /** * Check if admin has allowed access to a specific post meta key - * + * * @since 4.2.0 - * + * * @param string $meta_key The post meta key to test - * + * * @return bool True if this key can be accessed, false otherwise */ function wpcf7dtx_post_meta_key_access_is_allowed($meta_key) { // Get the DTX Settings - $settings = wpcf7dtx_get_settings();get_option('cf7dtx_settings', []); + $settings = wpcf7dtx_get_settings(); // Has access to all metadata been enabled? - if( isset($settings['post_meta_allow_all']) && $settings['post_meta_allow_all'] === 'enabled' ){ + if (isset($settings['post_meta_allow_all']) && $settings['post_meta_allow_all'] === 'enabled') { return true; } // If not, check the Allow List - - $allowed_keys; + $allowed_keys = array(); // No key list from settings - if( !isset($settings['post_meta_allow_keys'] ) || !is_string($settings['post_meta_allow_keys'])){ - $allowed_keys = []; - } - // Extract allowed keys from setting text area - else{ - // $allowed_keys = preg_split('/\r\n|\r|\n/', $settings['post_meta_allow_keys']); - $allowed_keys = wpcf7dtx_parse_allowed_keys( $settings['post_meta_allow_keys'] ); + if (isset($settings['post_meta_allow_keys']) && is_string($settings['post_meta_allow_keys'])) { + // Extract allowed keys from setting text area + $allowed_keys = wpcf7dtx_parse_allowed_keys($settings['post_meta_allow_keys']); } // Allow custom filters - $allowed_keys = apply_filters( 'wpcf7dtx_post_meta_key_allow_list', $allowed_keys ); + $allowed_keys = apply_filters('wpcf7dtx_post_meta_key_allow_list', $allowed_keys); // Check if the key is in the allow list - if( in_array( $meta_key, $allowed_keys ) ){ + if (in_array($meta_key, $allowed_keys)) { return true; // The key is allowed } // Everything is disallowed by default return false; - } - /** * Check if admin has allowed access to a specific user data - * + * * @since 4.2.0 - * + * * @param string $key The user data key to test - * + * * @return bool True if this key can be accessed, false otherwise */ -function wpcf7dtx_user_data_access_is_allowed( $key ) +function wpcf7dtx_user_data_access_is_allowed($key) { // Get the DTX Settings $settings = wpcf7dtx_get_settings(); //get_option('cf7dtx_settings', []); // Has access to all metadata been enabled? - if( isset($settings['user_data_allow_all']) && $settings['user_data_allow_all'] === 'enabled' ){ + if (isset($settings['user_data_allow_all']) && $settings['user_data_allow_all'] === 'enabled') { return true; } // If not, check the Allow List - - $allowed_keys; + $allowed_keys = array(); // No key list from settings - if( !isset($settings['user_data_allow_keys'] ) || !is_string($settings['user_data_allow_keys'])){ - $allowed_keys = []; - } - // Extract allowed keys from setting text area - else{ - // $allowed_keys = preg_split('/\r\n|\r|\n/', $settings['user_data_allow_keys']); + if (isset($settings['user_data_allow_keys']) && is_string($settings['user_data_allow_keys'])) { + // Extract allowed keys from setting text area $allowed_keys = wpcf7dtx_parse_allowed_keys($settings['user_data_allow_keys']); } // Allow custom filters - $allowed_keys = apply_filters( 'wpcf7dtx_user_data_key_allow_list', $allowed_keys ); + $allowed_keys = apply_filters('wpcf7dtx_user_data_key_allow_list', $allowed_keys); // Check if the key is in the allow list - if( in_array( $key, $allowed_keys ) ){ + if (in_array($key, $allowed_keys)) { return true; // The key is allowed } - // Everything is disallowed by default return false; - } - /** * Take the string saved in the options array from the allow list textarea and parse it into an array by newlines. * Also strip whitespace - * + * + * @since 4.2.0 + * * @param string $allowlist The string of allowed keys stored in the DB - * + * * @return array Array of allowed keys */ -function wpcf7dtx_parse_allowed_keys( $allowlist ){ +function wpcf7dtx_parse_allowed_keys($allowlist) +{ // Split by newlines - $keys = wpcf7dtx_split_newlines( $allowlist ); + $keys = wpcf7dtx_split_newlines($allowlist); // Trim whitespace - $keys = array_map( 'trim' , $keys ); + $keys = array_map('trim', $keys); return $keys; } -/** +/** * Used to parse strings stored in the database that are from text areas with one element per line into an array of strings - * + * + * @since 4.2.0 + * * @param string $str The multi-line string to be parsed into an array - * + * * @return array Array of parsed strings */ -function wpcf7dtx_split_newlines( $str ){ +function wpcf7dtx_split_newlines($str) +{ return preg_split('/\r\n|\r|\n/', $str); } /** * Gets the CF7 DTX settings field from the WP options table. Returns an empty array if option has not previously been set - * + * + * @since 4.2.0 + * * @return array The settings array */ -function wpcf7dtx_get_settings(){ - return get_option('cf7dtx_settings', []); +function wpcf7dtx_get_settings() +{ + return get_option('cf7dtx_settings', array()); } /** * Updates the CF7 DTX settings in the WP options table - * + * + * @since 4.2.0 + * * @param array $settings The settings array - * + * + * @return void + * */ -function wpcf7dtx_update_settings($settings){ - update_option( 'cf7dtx_settings', $settings ); +function wpcf7dtx_update_settings($settings) +{ + update_option('cf7dtx_settings', $settings); } /** * Outputs a useful PHP Warning message to users on how to allow-list denied meta and user keys - * + * + * @since 4.2.0 + * * @param string $key The post meta or user key to which access is currently denied * @param string $type Either 'post_meta' or 'user_data', used to display an appropriate message to the user + * + * @return void */ -function wpcf7dtx_access_denied_alert( $key, $type ){ - +function wpcf7dtx_access_denied_alert($key, $type) +{ // Only check on the front end - if( is_admin() || wp_doing_ajax() || wp_is_json_request() ) return; + if (is_admin() || wp_doing_ajax() || wp_is_json_request()) return; - $shortcode = ''; - $list_name = ''; - - switch( $type ){ + switch ($type) { case 'post_meta': $shortcode = 'CF7_get_custom_field'; $list_name = __('Meta Key Allow List', 'contact-form-7-dynamic-text-extension'); @@ -830,47 +849,21 @@ function wpcf7dtx_access_denied_alert( $key, $type ){ $shortcode = 'CF7_get_current_user'; $list_name = __('User Data Key Allow List', 'contact-form-7-dynamic-text-extension'); break; - default: + default: + $shortcode = ''; + $list_name = ''; + break; } $settings_page_url = admin_url('admin.php?page=cf7dtx_settings'); $msg = sprintf( - __('CF7 DTX: Access denied to key: "%1$s" in dynamic contact form shortcode: [%2$s]. Please add this key to the %3$s at %4$s','contact-form-7-dynamic-text-extension'), + __('CF7 DTX: Access denied to key: "%1$s" in dynamic contact form shortcode: [%2$s]. Please add this key to the %3$s at %4$s', 'contact-form-7-dynamic-text-extension'), $key, $shortcode, $list_name, $settings_page_url ); - trigger_error( $msg, E_USER_WARNING ); + trigger_error($msg, E_USER_WARNING); } - - -/** - * Helper function to output array and object data - */ -/* -function dtxpretty ($var, $print=true, $privobj=false) { - - $type = gettype($var); - - if( $privobj && $type === 'object' ){ - $p = ''.print_r($var, true).''; - } - else { - $p = '
'.$type . ' ' . json_encode( - $var, - JSON_UNESCAPED_SLASHES | - JSON_UNESCAPED_UNICODE | - JSON_PRETTY_PRINT | - JSON_PARTIAL_OUTPUT_ON_ERROR | - JSON_INVALID_UTF8_SUBSTITUTE - ).''; - } - if( $print ) { - echo $p; - } - return $p; -} -*/ \ No newline at end of file diff --git a/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/includes/validation.php b/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/includes/validation.php index 00d5bb49..47d9f6cb 100644 --- a/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/includes/validation.php +++ b/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/includes/validation.php @@ -1,369 +1,373 @@ - array( - 'description' => __('There is a field with an invalid email address', 'contact-form-7-dynamic-text-extension'), - 'default' => __('Please enter a valid email address.', 'contact-form-7-dynamic-text-extension') - ), - 'dtx_invalid_tel' => array( - 'description' => __('There is a field with an invalid phone number', 'contact-form-7-dynamic-text-extension'), - 'default' => __('Please enter a valid phone number.', 'contact-form-7-dynamic-text-extension') - ), - 'dtx_invalid_number' => array( - 'description' => __('There is a field with an invalid number', 'contact-form-7-dynamic-text-extension'), - 'default' => __('Please enter a valid number.', 'contact-form-7-dynamic-text-extension') - ), - 'dtx_invalid_date' => array( - 'description' => __('There is a field with an invalid date', 'contact-form-7-dynamic-text-extension'), - 'default' => __('Please enter a valid date.', 'contact-form-7-dynamic-text-extension') - ), - )); -} -add_filter('wpcf7_messages', 'wpcf7dtx_messages'); - -/** - * Add DTX Error Code to Config Validator - * - * @since 5.0.0 - * - * @param array $error_codes A sequential array of available error codes in Contact Form 7. - * - * @return array A modified sequential array of available error codes in Contact Form 7. - */ -function wpcf7dtx_config_validator_available_error_codes($error_codes) -{ - $dtx_errors = array('dtx_disallowed'); - return array_merge($error_codes, $dtx_errors); -} -add_filter('wpcf7_config_validator_available_error_codes', 'wpcf7dtx_config_validator_available_error_codes'); - -/** - * Validate DTX Form Fields - * - * Frontend validation for DTX form tags - * - * @param WPCF7_Validation $result the current validation result object - * @param WPCF7_FormTag $tag the current form tag being filtered for validation - * - * @return WPCF7_Validation a possibly modified validation result object - */ -function wpcf7dtx_validation_filter($result, $tag) -{ - $type = str_replace(array('dynamic_', 'dynamic'), '', $tag->basetype); - if (empty($tag->name) || in_array($type, array('hidden', 'submit', 'reset'))) { - return $result; // Bail early for tags without names or if a specific type - } - - // Get the value - $user_value = wpcf7dtx_array_has_key($tag->name, $_POST); - if (is_array($user_value)) { - $selection_count = count($user_value); - if (!wpcf7_form_tag_supports($tag->type, 'selectable-values')) { - // Field passed selectable values when it's doesn't support them - $result->invalidate($tag, wpcf7_get_message('validation_error')); - return $result; - } elseif ($selection_count > 1) { - if (!wpcf7_form_tag_supports($tag->type, 'multiple-controls-container')) { - // Field passed multiple values when it's doesn't support them - $result->invalidate($tag, wpcf7_get_message('validation_error')); - return $result; - } - foreach ($user_value as $selection) { - // Validate each selected choice - $result = wpcf7dtx_validate_value($result, sanitize_textarea_field(strval($selection)), $tag, $type); - if (!$result->is_valid($tag->name)) { - return $result; // Return early if any are invalid - } - } - return $result; - } - $user_value = sanitize_text_field(strval(implode(' ', $user_value))); - } elseif ($type == 'textarea') { - $user_value = sanitize_textarea_field(strval($user_value)); - } else { - $user_value = sanitize_text_field(strval($user_value)); - } - // Validate and return - return wpcf7dtx_validate_value($result, $user_value, $tag, $type); -} - - -/** - * Validate Single Value - * - * @param WPCF7_Validation $result the current validation result object - * @param string $value the current value being validated, sanitized - * @param WPCF7_FormTag $tag the current form tag being filtered for validation - * @param string $type Optional. The type of the current form tag. Default is blank for lookup. - * - * @return WPCF7_Validation a possibly modified validation result object - */ -function wpcf7dtx_validate_value($result, $value, $tag, $type = '') -{ - $type = $type ? $type : str_replace(array('dynamic_', 'dynamic'), '', $tag->basetype); - - // Validate required fields for value - if ($tag->is_required() && empty($value)) { - $result->invalidate($tag, wpcf7_get_message('invalid_required')); - return $result; - } - - // Validate value by type - if (!empty($value)) { - switch ($type) { - case 'email': - if (!wpcf7_is_email($value)) { - $result->invalidate($tag, wpcf7_get_message('dtx_invalid_email')); - return $result; - } - break; - case 'tel': - if (!wpcf7_is_tel($value)) { - $result->invalidate($tag, wpcf7_get_message('dtx_invalid_tel')); - return $result; - } - break; - case 'number': - case 'range': - if (!wpcf7_is_number($value)) { - $result->invalidate($tag, wpcf7_get_message('dtx_invalid_number')); - return $result; - } - break; - case 'date': - if (!wpcf7_is_date($value)) { - $result->invalidate($tag, wpcf7_get_message('dtx_invalid_date')); - return $result; - } - break; - } - - // Finish validating text-based inputs - $maxlength = $tag->get_maxlength_option(); - $minlength = $tag->get_minlength_option(); - if ($maxlength && $minlength && $maxlength < $minlength) { - $maxlength = $minlength = null; - } - $code_units = wpcf7_count_code_units($value); - if (false !== $code_units) { - if ($maxlength && $maxlength < $code_units) { - $result->invalidate($tag, wpcf7_get_message('invalid_too_long')); - return $result; - } elseif ($minlength && $code_units < $minlength) { - $result->invalidate($tag, wpcf7_get_message('invalid_too_short')); - return $result; - } - } - } - - return $result; -} - -/** - * Backend Mail Configuration Validation - * - * Validate dynamic form tags used in mail configuration. - * - * @since 4.0.0 - * - * @param WPCF7_ConfigValidator - * - * @return void - */ -function wpcf7dtx_validate($validator) -{ - // Check for sensitive form tags - $manager = WPCF7_FormTagsManager::get_instance(); - $contact_form = $validator->contact_form(); - $form = $contact_form->prop('form'); - if (wpcf7_autop_or_not()) { - $form = $manager->replace_with_placeholders($form); - $form = wpcf7_autop($form); - $form = $manager->restore_from_placeholders($form); - } - $form = $manager->replace_all($form); - $tags = $manager->get_scanned_tags(); - foreach ($tags as $tag) { - /** @var WPCF7_FormTag $tag */ - - // Only validate DTX formtags - if (in_array($tag->basetype, array_merge( - array('dynamictext', 'dynamichidden'), // Deprecated DTX form tags - array_keys(wpcf7dtx_config()) // DTX form tags - ))) { - // Check value for sensitive data - $default = $tag->get_option('defaultvalue', '', true); - if (!$default) { - $default = $tag->get_default_option(strval(reset($tag->values))); - } - if ( - !empty($value = trim(wpcf7_get_hangover($tag->name, $default))) && // Has value - ($result = wpcf7dtx_validate_sensitive_value($value))['status'] // Has sensitive data - ) { - $validator->add_error('form.body', 'dtx_disallowed', array( - 'message' => sprintf( - __('[%1$s %2$s]: Access to key "%3$s" in shortcode "%4$s" is disallowed by default. To allow access, add "%3$s" to the %5$s Allow List.', 'contact-form-7-dynamic-text-extension'), - esc_html($tag->basetype), - esc_html($tag->name), - esc_html($result['key']), - esc_html($result['shortcode']), - esc_html($result['shortcode'] == 'CF7_get_current_user' ? __('User Data Key', 'contact-form-7-dynamic-text-extension') : __('Meta Key', 'contact-form-7-dynamic-text-extension')) - ), - 'link' => wpcf7dtx_get_admin_settings_screen_url() - )); - } - - // Check placeholder for sensitive data - if ( - ($tag->has_option('placeholder') || $tag->has_option('watermark')) && // Using placeholder - !empty($placeholder = trim(html_entity_decode(urldecode($tag->get_option('placeholder', '', true)), ENT_QUOTES))) && // Has value - ($result = wpcf7dtx_validate_sensitive_value($placeholder))['status'] // Has sensitive data - ) { - $validator->add_error('form.body', 'dtx_disallowed', array( - 'message' => sprintf( - __('[%1$s %2$s]: Access to key "%3$s" in shortcode "%4$s" is disallowed by default. To allow access, add "%3$s" to the %5$s Allow List.', 'contact-form-7-dynamic-text-extension'), - esc_html($tag->basetype), - esc_html($tag->name), - esc_html($result['key']), - esc_html($result['shortcode']), - esc_html($result['shortcode'] == 'CF7_get_current_user' ? __('User Data Key', 'contact-form-7-dynamic-text-extension') : __('Meta Key', 'contact-form-7-dynamic-text-extension')) - ), - 'link' => wpcf7dtx_get_admin_settings_screen_url() - )); - } - } - } - - // Validate email address - if (!$validator->is_valid()) { - $contact_form = null; - $form_tags = null; - foreach ($validator->collect_error_messages() as $component => $errors) { - $components = explode('.', $component); - if (count($components) === 2 && strpos($components[0], 'mail') === 0 && in_array($components[1], array('sender', 'recipient', 'additional_headers'))) { - foreach ($errors as $error) { - // Focus on email fields that flag the invalid mailbox syntax warning, have to test link because code isn't sent and message could be in any language - if (strpos(wpcf7dtx_array_has_key('link', $error), 'invalid-mailbox-syntax') !== false) { - if (is_null($contact_form)) { - $contact_form = $validator->contact_form(); - } - if (is_null($form_tags)) { - $form_tags = wpcf7_scan_form_tags(); - } - $raw_value = $contact_form->prop($components[0])[$components[1]]; - foreach ($form_tags as $tag) { - if (!empty($tag->name)) { - // Check if this form tag is in the raw value - $form_tag = '[' . $tag->name . ']'; - if (strpos($raw_value, $form_tag) !== false && in_array($tag->basetype, array_keys(wpcf7dtx_config()))) { - $validator->remove_error($component, 'invalid_mailbox_syntax'); // Remove error, this is ours to handle now - $utm_source = urlencode(home_url()); - if (!in_array($tag->basetype, array('dynamic_hidden', 'dynamic_email'))) { - $validator->add_error($component, 'invalid_mailbox_syntax', array( - 'message' => __('Only email, dynamic email, hidden, or dynamic hidden form tags can be used for email addresses.', 'contact-form-7-dynamic-text-extension'), - 'link' => esc_url(sprintf('https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/configuration-errors/?utm_source=%s&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=config-error-invalid_mailbox_syntax#valid-form-tags', $utm_source)) - )); - } else { - $dynamic_value = wpcf7dtx_get_dynamic(false, $tag); // Get the dynamic value of this tag - if (empty($dynamic_value) && $tag->basetype == 'dynamic_hidden') { - $validator->add_error($component, 'maybe_empty', array( - 'message' => __('The dynamic hidden form tag must have a default value.', 'contact-form-7-dynamic-text-extension'), - 'link' => esc_url(sprintf('https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/configuration-errors/?utm_source=%s&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=config-error-maybe_empty#maybe-empty', $utm_source)) - )); - } elseif (empty($dynamic_value) && !$tag->is_required()) { - $validator->add_error($component, 'maybe_empty', array( - 'message' => __('The dynamic form tag must be required or have a default value.', 'contact-form-7-dynamic-text-extension'), - 'link' => esc_url(sprintf('https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/configuration-errors/?utm_source=%s&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=config-error-maybe_empty#maybe-empty', $utm_source)) - )); - } elseif (!empty($dynamic_value)) { - if (!wpcf7_is_email($dynamic_value)) { - $validator->add_error($component, 'invalid_mailbox_syntax', array( - 'message' => __('The default dynamic value does not result in a valid email address.', 'contact-form-7-dynamic-text-extension'), - 'link' => esc_url(sprintf('https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/configuration-errors/?utm_source=%s&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=config-error-invalid_mailbox_syntax#invalid-email-address', $utm_source)) - )); - } elseif ($component[1] == 'sender' && !wpcf7_is_email_in_site_domain($dynamic_value)) { - $validator->add_error($component, 'email_not_in_site_domain', array( - 'message' => __('The dynamic email address for the sender does not belong to the site domain.', 'contact-form-7-dynamic-text-extension'), - 'link' => esc_url(sprintf('https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/configuration-errors/?utm_source=%s&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=config-error-email_not_in_site_domain#invalid-site-domain', $utm_source)) - )); - } - } - } - } - } - } - } - } - } - } - } -} -add_action('wpcf7_config_validator_validate', 'wpcf7dtx_validate'); - -/** - * Validate Field Value for Sensitive Data - * - * @since 5.0.0 - * - * @see https://developer.wordpress.org/reference/functions/get_bloginfo/#description - * - * @param string $content The string to validate. - * - * @return array An associative array with keys `status` (bool), `shortcode` (string), and `key` (string). - * The value of `status` is true if the content is a shortcode that is attempting to access sensitive data. False - * otherwise. The value of `shortcode` is the the shortcode that is making the attempt if `status` is true. The - * value of `key` is the shortcode's `key` attribute of the attempt being made if `status` is true. - */ -function wpcf7dtx_validate_sensitive_value($content) -{ - $r = array( - 'status' => false, - 'shortcode' => '', - 'key' => '' - ); - - // Parse the attributes. [0] is the shortcode name. ['key'] is the key attribute - $atts = shortcode_parse_atts($content); - - // If we can't extract the atts, or the shortcode or `key` is not an att, don't validate - if( !is_array($atts) || !array_key_exists('key', $atts) || !array_key_exists('0', $atts) ) return $r; - - // Find the key and shortcode in question - $key = sanitize_text_field($atts['key']); - $shortcode = sanitize_text_field($atts['0']); - - // If the shortcode or key value does not exist, don't validate - if( empty($shortcode) || empty($key) ) return $r; - - $allowed = true; - switch( $shortcode ){ - case 'CF7_get_custom_field': - $allowed = wpcf7dtx_post_meta_key_access_is_allowed( $key ); - break; - case 'CF7_get_current_user': - $allowed = wpcf7dtx_user_data_access_is_allowed( $key ); - break; - default: - - } - - if( !$allowed ){ - $r['status'] = true; - $r['shortcode'] = $shortcode; - $r['key'] = $key; - } - - return $r; - -} + array( + 'description' => __('There is a field with an invalid email address', 'contact-form-7-dynamic-text-extension'), + 'default' => __('Please enter a valid email address.', 'contact-form-7-dynamic-text-extension') + ), + 'dtx_invalid_tel' => array( + 'description' => __('There is a field with an invalid phone number', 'contact-form-7-dynamic-text-extension'), + 'default' => __('Please enter a valid phone number.', 'contact-form-7-dynamic-text-extension') + ), + 'dtx_invalid_number' => array( + 'description' => __('There is a field with an invalid number', 'contact-form-7-dynamic-text-extension'), + 'default' => __('Please enter a valid number.', 'contact-form-7-dynamic-text-extension') + ), + 'dtx_invalid_date' => array( + 'description' => __('There is a field with an invalid date', 'contact-form-7-dynamic-text-extension'), + 'default' => __('Please enter a valid date.', 'contact-form-7-dynamic-text-extension') + ), + )); +} +add_filter('wpcf7_messages', 'wpcf7dtx_messages'); + +/** + * Add DTX Error Code to Config Validator + * + * @since 5.0.0 + * + * @param array $error_codes A sequential array of available error codes in Contact Form 7. + * + * @return array A modified sequential array of available error codes in Contact Form 7. + */ +function wpcf7dtx_config_validator_available_error_codes($error_codes) +{ + $dtx_errors = array('dtx_disallowed'); + return array_merge($error_codes, $dtx_errors); +} +add_filter('wpcf7_config_validator_available_error_codes', 'wpcf7dtx_config_validator_available_error_codes'); + +/** + * Validate DTX Form Fields + * + * Frontend validation for DTX form tags + * + * @param WPCF7_Validation $result the current validation result object + * @param WPCF7_FormTag $tag the current form tag being filtered for validation + * + * @return WPCF7_Validation a possibly modified validation result object + */ +function wpcf7dtx_validation_filter($result, $tag) +{ + $type = str_replace(array('dynamic_', 'dynamic'), '', $tag->basetype); + if (empty($tag->name) || in_array($type, array('hidden', 'submit', 'reset'))) { + return $result; // Bail early for tags without names or if a specific type + } + + // Get the value + $user_value = wpcf7dtx_array_has_key($tag->name, $_POST); + if (is_array($user_value)) { + $selection_count = count($user_value); + if (!wpcf7_form_tag_supports($tag->type, 'selectable-values')) { + // Field passed selectable values when it's doesn't support them + $result->invalidate($tag, wpcf7_get_message('validation_error')); + return $result; + } elseif ($selection_count > 1) { + if (!wpcf7_form_tag_supports($tag->type, 'multiple-controls-container')) { + // Field passed multiple values when it's doesn't support them + $result->invalidate($tag, wpcf7_get_message('validation_error')); + return $result; + } + foreach ($user_value as $selection) { + // Validate each selected choice + $result = wpcf7dtx_validate_value($result, sanitize_textarea_field(strval($selection)), $tag, $type); + if (!$result->is_valid($tag->name)) { + return $result; // Return early if any are invalid + } + } + return $result; + } + $user_value = sanitize_text_field(strval(implode(' ', $user_value))); + } elseif ($type == 'textarea') { + $user_value = sanitize_textarea_field(strval($user_value)); + } else { + $user_value = sanitize_text_field(strval($user_value)); + } + // Validate and return + return wpcf7dtx_validate_value($result, $user_value, $tag, $type); +} + + +/** + * Validate Single Value + * + * @param WPCF7_Validation $result the current validation result object + * @param string $value the current value being validated, sanitized + * @param WPCF7_FormTag $tag the current form tag being filtered for validation + * @param string $type Optional. The type of the current form tag. Default is blank for lookup. + * + * @return WPCF7_Validation a possibly modified validation result object + */ +function wpcf7dtx_validate_value($result, $value, $tag, $type = '') +{ + $type = $type ? $type : str_replace(array('dynamic_', 'dynamic'), '', $tag->basetype); + + // Validate required fields for value + if ($tag->is_required() && empty($value)) { + $result->invalidate($tag, wpcf7_get_message('invalid_required')); + return $result; + } + + // Validate value by type + if (!empty($value)) { + switch ($type) { + case 'email': + if (!wpcf7_is_email($value)) { + $result->invalidate($tag, wpcf7_get_message('dtx_invalid_email')); + return $result; + } + break; + case 'tel': + if (!wpcf7_is_tel($value)) { + $result->invalidate($tag, wpcf7_get_message('dtx_invalid_tel')); + return $result; + } + break; + case 'number': + case 'range': + if (!wpcf7_is_number($value)) { + $result->invalidate($tag, wpcf7_get_message('dtx_invalid_number')); + return $result; + } + break; + case 'date': + if (!wpcf7_is_date($value)) { + $result->invalidate($tag, wpcf7_get_message('dtx_invalid_date')); + return $result; + } + break; + } + + // Finish validating text-based inputs + $maxlength = $tag->get_maxlength_option(); + $minlength = $tag->get_minlength_option(); + if ($maxlength && $minlength && $maxlength < $minlength) { + $maxlength = $minlength = null; + } + $code_units = wpcf7_count_code_units($value); + if (false !== $code_units) { + if ($maxlength && $maxlength < $code_units) { + $result->invalidate($tag, wpcf7_get_message('invalid_too_long')); + return $result; + } elseif ($minlength && $code_units < $minlength) { + $result->invalidate($tag, wpcf7_get_message('invalid_too_short')); + return $result; + } + } + } + + return $result; +} + +/** + * Validator Requires Contact Form 7 Minimum Version + */ +if (wpcf7dtx_dependencies()) { + /** + * Backend Mail Configuration Validation + * + * Validate dynamic form tags used in mail configuration. + * + * @since 4.0.0 + * + * @param WPCF7_ConfigValidator + * + * @return void + */ + function wpcf7dtx_validate($validator) + { + // Check for sensitive form tags + $manager = WPCF7_FormTagsManager::get_instance(); + $contact_form = $validator->contact_form(); + $form = $contact_form->prop('form'); + if (wpcf7_autop_or_not()) { + $form = $manager->replace_with_placeholders($form); + $form = wpcf7_autop($form); + $form = $manager->restore_from_placeholders($form); + } + $form = $manager->replace_all($form); + $tags = $manager->get_scanned_tags(); + foreach ($tags as $tag) { + /** @var WPCF7_FormTag $tag */ + + // Only validate DTX formtags + if (in_array($tag->basetype, array_merge( + array('dynamictext', 'dynamichidden'), // Deprecated DTX form tags + array_keys(wpcf7dtx_config()) // DTX form tags + ))) { + // Check value for sensitive data + $default = $tag->get_option('defaultvalue', '', true); + if (!$default) { + $default = $tag->get_default_option(strval(reset($tag->values))); + } + if ( + !empty($value = trim(wpcf7_get_hangover($tag->name, $default))) && // Has value + ($result = wpcf7dtx_validate_sensitive_value($value))['status'] // Has sensitive data + ) { + $validator->add_error('form.body', 'dtx_disallowed', array( + 'message' => sprintf( + __('[%1$s %2$s]: Access to key "%3$s" in shortcode "%4$s" is disallowed by default. To allow access, add "%3$s" to the %5$s Allow List.', 'contact-form-7-dynamic-text-extension'), + esc_html($tag->basetype), + esc_html($tag->name), + esc_html($result['key']), + esc_html($result['shortcode']), + esc_html($result['shortcode'] == 'CF7_get_current_user' ? __('User Data Key', 'contact-form-7-dynamic-text-extension') : __('Meta Key', 'contact-form-7-dynamic-text-extension')) + ), + 'link' => wpcf7dtx_get_admin_settings_screen_url() + )); + } + + // Check placeholder for sensitive data + if ( + ($tag->has_option('placeholder') || $tag->has_option('watermark')) && // Using placeholder + !empty($placeholder = trim(html_entity_decode(urldecode($tag->get_option('placeholder', '', true)), ENT_QUOTES))) && // Has value + ($result = wpcf7dtx_validate_sensitive_value($placeholder))['status'] // Has sensitive data + ) { + $validator->add_error('form.body', 'dtx_disallowed', array( + 'message' => sprintf( + __('[%1$s %2$s]: Access to key "%3$s" in shortcode "%4$s" is disallowed by default. To allow access, add "%3$s" to the %5$s Allow List.', 'contact-form-7-dynamic-text-extension'), + esc_html($tag->basetype), + esc_html($tag->name), + esc_html($result['key']), + esc_html($result['shortcode']), + esc_html($result['shortcode'] == 'CF7_get_current_user' ? __('User Data Key', 'contact-form-7-dynamic-text-extension') : __('Meta Key', 'contact-form-7-dynamic-text-extension')) + ), + 'link' => wpcf7dtx_get_admin_settings_screen_url() + )); + } + } + } + + // Validate email address + if (!$validator->is_valid()) { + $contact_form = null; + $form_tags = null; + foreach ($validator->collect_error_messages() as $component => $errors) { + $components = explode('.', $component); + if (count($components) === 2 && strpos($components[0], 'mail') === 0 && in_array($components[1], array('sender', 'recipient', 'additional_headers'))) { + foreach ($errors as $error) { + // Focus on email fields that flag the invalid mailbox syntax warning, have to test link because code isn't sent and message could be in any language + if (strpos(wpcf7dtx_array_has_key('link', $error), 'invalid-mailbox-syntax') !== false) { + if (is_null($contact_form)) { + $contact_form = $validator->contact_form(); + } + if (is_null($form_tags)) { + $form_tags = wpcf7_scan_form_tags(); + } + $raw_value = $contact_form->prop($components[0])[$components[1]]; + foreach ($form_tags as $tag) { + if (!empty($tag->name)) { + // Check if this form tag is in the raw value + $form_tag = '[' . $tag->name . ']'; + if (strpos($raw_value, $form_tag) !== false && in_array($tag->basetype, array_keys(wpcf7dtx_config()))) { + $validator->remove_error($component, 'invalid_mailbox_syntax'); // Remove error, this is ours to handle now + $utm_source = urlencode(home_url()); + if (!in_array($tag->basetype, array('dynamic_hidden', 'dynamic_email'))) { + $validator->add_error($component, 'invalid_mailbox_syntax', array( + 'message' => __('Only email, dynamic email, hidden, or dynamic hidden form tags can be used for email addresses.', 'contact-form-7-dynamic-text-extension'), + 'link' => esc_url(sprintf('https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/configuration-errors/?utm_source=%s&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=config-error-invalid_mailbox_syntax#valid-form-tags', $utm_source)) + )); + } else { + $dynamic_value = wpcf7dtx_get_dynamic(false, $tag); // Get the dynamic value of this tag + if (empty($dynamic_value) && $tag->basetype == 'dynamic_hidden') { + $validator->add_error($component, 'maybe_empty', array( + 'message' => __('The dynamic hidden form tag must have a default value.', 'contact-form-7-dynamic-text-extension'), + 'link' => esc_url(sprintf('https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/configuration-errors/?utm_source=%s&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=config-error-maybe_empty#maybe-empty', $utm_source)) + )); + } elseif (empty($dynamic_value) && !$tag->is_required()) { + $validator->add_error($component, 'maybe_empty', array( + 'message' => __('The dynamic form tag must be required or have a default value.', 'contact-form-7-dynamic-text-extension'), + 'link' => esc_url(sprintf('https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/configuration-errors/?utm_source=%s&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=config-error-maybe_empty#maybe-empty', $utm_source)) + )); + } elseif (!empty($dynamic_value)) { + if (!wpcf7_is_email($dynamic_value)) { + $validator->add_error($component, 'invalid_mailbox_syntax', array( + 'message' => __('The default dynamic value does not result in a valid email address.', 'contact-form-7-dynamic-text-extension'), + 'link' => esc_url(sprintf('https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/configuration-errors/?utm_source=%s&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=config-error-invalid_mailbox_syntax#invalid-email-address', $utm_source)) + )); + } elseif ($component[1] == 'sender' && !wpcf7_is_email_in_site_domain($dynamic_value)) { + $validator->add_error($component, 'email_not_in_site_domain', array( + 'message' => __('The dynamic email address for the sender does not belong to the site domain.', 'contact-form-7-dynamic-text-extension'), + 'link' => esc_url(sprintf('https://aurisecreative.com/docs/contact-form-7-dynamic-text-extension/configuration-errors/?utm_source=%s&utm_medium=link&utm_campaign=contact-form-7-dynamic-text-extension&utm_content=config-error-email_not_in_site_domain#invalid-site-domain', $utm_source)) + )); + } + } + } + } + } + } + } + } + } + } + } + } + add_action('wpcf7_config_validator_validate', 'wpcf7dtx_validate'); +} + + +/** + * Validate Field Value for Sensitive Data + * + * @since 5.0.0 + * + * @see https://developer.wordpress.org/reference/functions/get_bloginfo/#description + * + * @param string $content The string to validate. + * + * @return array An associative array with keys `status` (bool), `shortcode` (string), and `key` (string). + * The value of `status` is true if the content is a shortcode that is attempting to access sensitive data. False + * otherwise. The value of `shortcode` is the the shortcode that is making the attempt if `status` is true. The + * value of `key` is the shortcode's `key` attribute of the attempt being made if `status` is true. + */ +function wpcf7dtx_validate_sensitive_value($content) +{ + $r = array( + 'status' => false, + 'shortcode' => '', + 'key' => '' + ); + + // Parse the attributes. [0] is the shortcode name. ['key'] is the key attribute + $atts = shortcode_parse_atts($content); + + // If we can't extract the atts, or the shortcode or `key` is not an att, don't validate + if (!is_array($atts) || !array_key_exists('key', $atts) || !array_key_exists('0', $atts)) return $r; + + // Find the key and shortcode in question + $key = sanitize_text_field($atts['key']); + $shortcode = sanitize_text_field($atts['0']); + + // If the shortcode or key value does not exist, don't validate + if (empty($shortcode) || empty($key)) return $r; + + $allowed = true; + switch ($shortcode) { + case 'CF7_get_custom_field': + $allowed = wpcf7dtx_post_meta_key_access_is_allowed($key); + break; + case 'CF7_get_current_user': + $allowed = wpcf7dtx_user_data_access_is_allowed($key); + break; + default: + } + + if (!$allowed) { + $r['status'] = true; + $r['shortcode'] = $shortcode; + $r['key'] = $key; + } + + return $r; +} diff --git a/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/readme.txt b/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/readme.txt index c9d9d1e3..b45db4e9 100644 --- a/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/readme.txt +++ b/wp/wp-content/plugins/contact-form-7-dynamic-text-extension/readme.txt @@ -3,7 +3,7 @@ Contributors: sevenspark, tessawatkinsllc Donate link: https://just1voice.com/donate/ Tags: Contact Form 7, autofill, prepopulate, input, form field, contact form, text, hidden, input, dynamic, GET, POST, title, slug, auto-fill, pre-populate Tested up to: 6.4.2 -Stable tag: 4.2.0 +Stable tag: 4.2.3 This plugin provides additional form tags for the Contact Form 7 plugin. It allows dynamic generation of content for text-based input fields like text, hidden, and email, checkboxes, radio buttons, and drop-down selections using any shortcode. @@ -380,16 +380,35 @@ Please check out the [FAQ on our website](https://aurisecreative.com/docs/contac == Upgrade Notice == -= 4.2.0 = -Extend functionality without losing your work! += 4.2.3 = +Resolved a bug where the `dynamic_select` displayed with a default size of 40 instead of 1. == Changelog == += 4.2.3 = + +* Fix: Resolved a bug where the `dynamic_select` displayed with a default size of 40 instead of 1. + += 4.2.2 = + +* Feature: Cache compatibility JavaScript triggers the custom `dtx_init` event on enabled input fields, [see support thread](https://wordpress.org/support/topic/dynamic_text-cf7_url-dont-fire-onchange-event/). + += 4.2.1 = + +* Feature: Allows text-based fields to use `autocapitalize` attribute +* Feature: Allows text-based fields to use `autofocus` attribute +* Feature: Allows text-based fields to use `list` attribute +* Feature: Allows text-based fields to use `pattern` attribute +* Feature: Allows textareas to use `wrap` attribute +* Fix: Resolved the bug that prevented the `dynamic_date` shortcode from using `min`, `max`, and `step` attributes, [see support thread](https://wordpress.org/support/topic/dynamic_date-min-max-step-options-ignored/). +* Fix: Added minimum version check for Contact Form 7, [see support thread](https://wordpress.org/support/topic/str_contains-is-php-8-0-only-broken-compatibility/). +* Fix: Resolved an issue that used a function introduced in PHP 8 while plugin compatibility setting is currently still set to 7.4+, [see support thread](https://wordpress.org/support/topic/str_contains-is-php-8-0-only-broken-compatibility/). + = 4.2.0 = * Security Update: ** Please be sure to review this doc, as you may need to adjust the settings: https://sevenspark.com/docs/contact-form-7-dynamic-text-extension/allow-data-access ** * Feature: Added Settings Screen with Allow Lists -* Feature: Added Form Scanner +* Feature: Added Form Scanner * Feature: Added Allow List key validation in CF7 Form Validator = 4.1.0 = diff --git a/wp/wp-content/plugins/contact-form-7/includes/formatting.php b/wp/wp-content/plugins/contact-form-7/includes/formatting.php index ab89c44e..3bf78135 100644 --- a/wp/wp-content/plugins/contact-form-7/includes/formatting.php +++ b/wp/wp-content/plugins/contact-form-7/includes/formatting.php @@ -261,7 +261,7 @@ function wpcf7_canonicalize( $text, $args = '' ) { * @return string Sanitized unit-tag. */ function wpcf7_sanitize_unit_tag( $tag ) { - $tag = preg_replace( '/[^A-Za-z0-9_-]/', '', $tag ); + $tag = preg_replace( '/[^A-Za-z0-9_-]/', '', (string) $tag ); return $tag; } diff --git a/wp/wp-content/plugins/contact-form-7/includes/rest-api.php b/wp/wp-content/plugins/contact-form-7/includes/rest-api.php index b3ff055a..e1a7d697 100644 --- a/wp/wp-content/plugins/contact-form-7/includes/rest-api.php +++ b/wp/wp-content/plugins/contact-form-7/includes/rest-api.php @@ -355,6 +355,13 @@ class WPCF7_REST_Controller { $request->get_param( '_wpcf7_unit_tag' ) ); + if ( empty( $unit_tag ) ) { + return new WP_Error( 'wpcf7_unit_tag_not_found', + __( "There is no valid unit tag.", 'contact-form-7' ), + array( 'status' => 400 ) + ); + } + $result = $item->submit(); $response = array_merge( $result, array( diff --git a/wp/wp-content/plugins/contact-form-7/modules/sendinblue/sendinblue.php b/wp/wp-content/plugins/contact-form-7/modules/sendinblue/sendinblue.php index 23c08edf..6a42e2fa 100644 --- a/wp/wp-content/plugins/contact-form-7/modules/sendinblue/sendinblue.php +++ b/wp/wp-content/plugins/contact-form-7/modules/sendinblue/sendinblue.php @@ -219,6 +219,18 @@ function wpcf7_sendinblue_collect_parameters() { } } + $params = array_map( + function ( $param ) { + if ( is_array( $param ) ) { + $param = wpcf7_array_flatten( $param ); + $param = reset( $param ); + } + + return $param; + }, + $params + ); + $params = apply_filters( 'wpcf7_sendinblue_collect_parameters', $params diff --git a/wp/wp-content/plugins/contact-form-7/readme.txt b/wp/wp-content/plugins/contact-form-7/readme.txt index ea80793d..5a938ef8 100644 --- a/wp/wp-content/plugins/contact-form-7/readme.txt +++ b/wp/wp-content/plugins/contact-form-7/readme.txt @@ -5,7 +5,7 @@ Tags: contact, form, contact form, feedback, email, ajax, captcha, akismet, mult Requires at least: 6.2 Requires PHP: 7.4 Tested up to: 6.4 -Stable tag: 5.8.6 +Stable tag: 5.8.7 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html @@ -78,6 +78,10 @@ Do you have questions or issues with Contact Form 7? Use these support channels For more information, see [Releases](https://contactform7.com/category/releases/). += 5.8.7 = + +[https://contactform7.com/contact-form-7-587/](https://contactform7.com/contact-form-7-587/) + = 5.8.6 = [https://contactform7.com/contact-form-7-586/](https://contactform7.com/contact-form-7-586/) diff --git a/wp/wp-content/plugins/contact-form-7/wp-contact-form-7.php b/wp/wp-content/plugins/contact-form-7/wp-contact-form-7.php index 1f85730b..1c63002a 100644 --- a/wp/wp-content/plugins/contact-form-7/wp-contact-form-7.php +++ b/wp/wp-content/plugins/contact-form-7/wp-contact-form-7.php @@ -7,12 +7,12 @@ * Author URI: https://ideasilo.wordpress.com/ * License: GPL v2 or later * License URI: https://www.gnu.org/licenses/gpl-2.0.html - * Version: 5.8.6 + * Version: 5.8.7 * Requires at least: 6.2 * Requires PHP: 7.4 */ -define( 'WPCF7_VERSION', '5.8.6' ); +define( 'WPCF7_VERSION', '5.8.7' ); define( 'WPCF7_REQUIRED_WP_VERSION', '6.2' ); diff --git a/wp/wp-content/plugins/ip-geo-block/LICENSE.txt b/wp/wp-content/plugins/ip-geo-block/LICENSE.txt deleted file mode 100644 index f288702d..00000000 --- a/wp/wp-content/plugins/ip-geo-block/LICENSE.txt +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc.
'; - if ( 'updated' === $type ) - echo '', IP_Geo_Block_Util::kses( $msg ), ''; - else - echo 'IP Geo Block: ', IP_Geo_Block_Util::kses( $msg ); - echo '
%s. It seems to have failed downloading ZIP file from WordPress-IP-Geo-API. Try to deactivate IP Geo Block once and activate it again, or install ip-geo-api with write permission according to this instruction.', 'ip-geo-block' ),
- apply_filters( 'ip-geo-block-api-dir', $settings['api_dir'] ? $settings['api_dir'] : basename( WP_CONTENT_DIR ) )
- ) );
- }
-
- else {
- $providers = IP_Geo_Block_Provider::get_valid_providers( $settings, FALSE, FALSE, TRUE );
- if ( empty( $providers ) ) {
- $this->add_admin_notice( 'error', sprintf(
- __( 'You should select at least one API at Geolocation API settings. Otherwise you\'ll be blocked after the cache expires.', 'ip-geo-block' ),
- esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => 0, 'sec' => 4 ), $network ) ) . '#' . IP_Geo_Block::PLUGIN_NAME . '-section-4'
- ) );
- }
-
- else {
- $providers = IP_Geo_Block_Provider::get_addons( $settings['providers'] );
- if ( empty( $providers ) ) {
- $this->add_admin_notice( 'error', sprintf(
- __( 'You should select at least one API for local database at Geolocation API settings. Otherwise access to the external API may slow down the site.', 'ip-geo-block' ),
- esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => 0, 'sec' => 4 ), $network ) ) . '#' . IP_Geo_Block::PLUGIN_NAME . '-section-4'
- ) );
- }
- }
- }
-
- // Check consistency of matching rule
- if ( -1 === (int)$settings['matching_rule'] ) {
- if ( FALSE !== $updating ) {
- self::add_admin_notice( 'notice-warning', sprintf(
- __( 'Now downloading geolocation databases in background. After a little while, please check your country code and “Matching rule” at Validation rules and behavior.', 'ip-geo-block' ),
- esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME ), $network ) )
- ) );
- }
- else {
- self::add_admin_notice( 'error', sprintf(
- __( 'The “Matching rule” is not set properly. Please confirm it at Validation rules and behavior.', 'ip-geo-block' ),
- esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME ), $network ) )
- ) );
- }
- }
-
- // Check to finish updating matching rule
- elseif ( 'done' === $updating ) {
- delete_transient( IP_Geo_Block::CRON_NAME );
- self::add_admin_notice( 'updated ', __( 'Local database and matching rule have been updated.', 'ip-geo-block' ) );
- }
-
- // Check self blocking (skip during updating)
- if ( FALSE === $updating && 1 === (int)$settings['validation']['login'] ) {
- $instance = IP_Geo_Block::get_instance();
- $validate = $instance->validate_ip( 'login', $settings, TRUE, FALSE ); // skip authentication check
-
- switch( $validate['result'] ) {
- case 'limited':
- self::add_admin_notice( 'error',
- __( 'Once you logout, you will be unable to login again because the number of login attempts reaches the limit.', 'ip-geo-block' ) . ' ' .
- sprintf(
- __( 'Please remove your IP address in “%1$sStatistics in IP address cache%2$s” on “%3$sStatistics%4$s” tab to prevent locking yourself out.', 'ip-geo-block' ),
- '', '',
- '', ''
- )
- );
- break;
-
- case 'blocked':
- case 'extra':
- self::add_admin_notice( 'error',
- ( $settings['matching_rule'] ?
- __( 'Once you logout, you will be unable to login again because your country code or IP address is in the blacklist.', 'ip-geo-block' ) :
- __( 'Once you logout, you will be unable to login again because your country code or IP address is not in the whitelist.', 'ip-geo-block' )
- ) . ' ' .
- ( 'ZZ' !== $validate['code'] ?
- sprintf(
- __( 'Please check your “%sValidation rules and behavior%s”.', 'ip-geo-block' ),
- '', ''
- ) :
- sprintf(
- __( 'Please confirm your local geolocation database files exist at “%sLocal database settings%s” section, or remove your IP address in cache at “%sStatistics in cache%s” section.', 'ip-geo-block' ),
- '', '',
- '', ''
- )
- )
- );
- break;
- }
- }
-
- // Check consistency of emergency login link
- if ( isset( $settings['login_link'] ) && $settings['login_link']['link'] && ! IP_Geo_Block_Util::verify_link( $settings['login_link']['link'], $settings['login_link']['hash'] ) ) {
- self::add_admin_notice( 'error',
- sprintf(
- __( 'Emergency login link is outdated. Please delete it once and generate again at “%sPlugin settings%s” section. Also do not forget to update favorites / bookmarks in your browser.', 'ip-geo-block' ),
- '', ''
- )
- );
- }
-
- // Check activation of IP Geo Allow
- if ( $settings['validation']['timing'] && is_plugin_active( 'ip-geo-allow/index.php' ) ) {
- self::add_admin_notice( 'error',
- __( '“mu-plugins” (ip-geo-block-mu.php) at “Validation timing” is imcompatible with IP Geo Allow. Please select “init” action hook.', 'ip-geo-block' )
- );
- }
- }
-
- /**
- * Setup menu and option page for this plugin
- *
- */
- public function setup_admin_page() {
- $settings = IP_Geo_Block::get_option();
-
- // Register the administration menu.
- $this->add_plugin_admin_menu( $settings );
-
- // Avoid multiple validation.
- if ( 'GET' === $_SERVER['REQUEST_METHOD'] )
- $this->diagnose_admin_screen( $settings );
-
- // Register settings page only if it is needed.
- if ( ( isset( $_GET ['page' ] ) && IP_Geo_Block::PLUGIN_NAME === $_GET ['page' ] ) ||
- ( isset( $_POST['option_page'] ) && IP_Geo_Block::PLUGIN_NAME === $_POST['option_page'] ) ) {
- $this->register_settings_tab();
- }
-
- // Add an action link pointing to the options page. @since 2.7
- else {
- add_filter( 'plugin_row_meta', array( $this, 'add_plugin_meta_links' ), 10, 2 );
- add_filter( 'plugin_action_links_' . IP_GEO_BLOCK_BASE, array( $this, 'add_action_links' ), 10, 1 );
- }
-
- // Register scripts for admin.
- add_action( 'admin_enqueue_scripts', array( 'IP_Geo_Block', 'enqueue_nonce' ), 0 );
-
- // Show admin notices at the place where it should be. @since 2.5.0
- add_action( 'admin_notices', array( $this, 'show_admin_notices' ) );
- add_action( 'network_admin_notices', array( $this, 'show_admin_notices' ) );
- }
-
- /**
- * Get cookie that indicates open/close section
- *
- */
- public function get_cookie() {
- static $cookie = array();
-
- if ( empty( $cookie ) && ! empty( $_COOKIE[ IP_Geo_Block::PLUGIN_NAME ] ) ) {
- foreach ( explode( '&', $_COOKIE[ IP_Geo_Block::PLUGIN_NAME ] ) as $i => $v ) {
- list( $i, $v ) = explode( '=', $v );
- $cookie[ $i ] = str_split( $v );
- }
- }
-
- return $cookie;
- }
-
- /**
- * Prints out all settings sections added to a particular settings page
- *
- * wp-admin/includes/template.php @since 2.7.0
- */
- private function do_settings_sections( $page, $tab ) {
- global $wp_settings_sections, $wp_settings_fields;
-
- // target section to be opened
- $target = isset( $_GET['sec'] ) ? (int)$_GET['sec'] : -1;
-
- if ( isset( $wp_settings_sections[ $page ] ) ) {
- $index = 0; // index of fieldset
- $cookie = $this->get_cookie();
-
- foreach ( (array) $wp_settings_sections[ $page ] as $section ) {
- // TRUE if open ('o') or FALSE if close ('x')
- $stat = empty( $cookie[ $tab ][ $index ] ) || 'x' !== $cookie[ $tab ][ $index ] || $index === $target;
-
- echo "\n", '\n";
- ++$index;
- }
- }
- }
-
- /**
- * Render the settings page for this plugin.
- *
- */
- public function display_plugin_admin_page() {
- $tab = $this->admin_tab;
- $tabs = array(
- 5 => __( 'Sites list', 'ip-geo-block' ),
- 0 => __( 'Settings', 'ip-geo-block' ),
- 1 => __( 'Statistics', 'ip-geo-block' ),
- 4 => __( 'Logs', 'ip-geo-block' ),
- 2 => __( 'Search', 'ip-geo-block' ),
- 3 => __( 'Attribution', 'ip-geo-block' ),
- );
-
- $settings = IP_Geo_Block::get_option();
- $cookie = $this->get_cookie();
- $title = esc_html( get_admin_page_title() );
-
- // Target page that depends on the network multisite or not.
- if ( 'options-general.php' === $GLOBALS['pagenow'] ) {
- $action = 'options.php';
- unset( $tabs[5] ); // Sites list
- if ( $this->is_network_admin ) {
- $title .= ' ';
- }
- }
-
- // '/wp-admin/network/admin.php'
- else {
- // `edit.php` is an action handler for Multisite administration dashboard.
- // `edit.php` ==> do action `network_admin_edit_ip-geo-block` ==> `validate_network_settings()`
- $action = 'edit.php?action=' . IP_Geo_Block::PLUGIN_NAME;
- if ( $this->is_network_admin ) {
- unset( $tabs[1], $tabs[4], $tabs[2], $tabs[3] ); // Statistics, Logs, Search, Attribution
- $title .= ' ';
- }
- }
-
-?>
-', implode( '
', $tab ), "
', __( 'Thanks for providing these great services for free.', 'ip-geo-block' ), "
\n";
- echo __( '(Most browsers will redirect you to each site without referrer when you click the link.)', 'ip-geo-block' ), "
', $desc, "
\n"; - - if ( 'select' === $args['type'] ) - break; - - echo "%s. Please check the permission.', 'ip-geo-block' ), '' . $file . ''
- ) );
- }
-
- // Force to finish update matching rule
- delete_transient( IP_Geo_Block::CRON_NAME );
-
- // start to update databases immediately
- do_action( IP_Geo_Block::PLUGIN_NAME . '-settings-updated', $options, TRUE );
-
- return $options;
- }
-
- /**
- * Validate settings and configure some features for network multisite.
- *
- * @see https://vedovini.net/2015/10/using-the-wordpress-settings-api-with-network-admin-pages/
- */
- public function validate_network_settings() {
- // Must check that the user has the required capability
- $this->check_admin_post( FALSE );
-
- // The list of registered options (IP_Geo_Block::OPTION_NAME).
- global $new_whitelist_options;
- $options = $new_whitelist_options[ IP_Geo_Block::PLUGIN_NAME ];
-
- // Go through the posted data and save the targetted options.
- foreach ( $options as $option ) {
- if ( isset( $_POST[ $option ] ) ) {
- $this->update_multisite_settings( $_POST[ $option ] );
- }
- }
-
- // Register a settings error to be displayed to the user
- self::add_admin_notice( 'updated', __( 'Settings saved.' ) );
-
- // Redirect in order to back to the settings page.
- wp_redirect( esc_url_raw(
- add_query_arg(
- array( 'page' => IP_Geo_Block::PLUGIN_NAME ),
- $this->dashboard_url( ! empty( $_POST[ $option ]['network_wide'] ) )
- )
- ) );
-
- exit;
- }
-
- /**
- * Update option in all blogs.
- *
- * @note: This function triggers `validate_settings()` on register_setting() in wp-include/option.php.
- */
- public function update_multisite_settings( $settings ) {
- global $wpdb;
- $blog_ids = $wpdb->get_col( "SELECT `blog_id` FROM `$wpdb->blogs`" );
- $ret = TRUE;
-
- foreach ( $blog_ids as $id ) {
- switch_to_blog( $id );
- $map = IP_Geo_Block::get_option( FALSE );
- $settings['api_key']['GoogleMap'] = $map['api_key']['GoogleMap'];
- $ret &= IP_Geo_Block::update_option( $settings, FALSE );
- restore_current_blog();
- }
-
- return $ret;
- }
-
- /**
- * Analyze entries in "Validation logs"
- *
- * @param array $logs An array including each entry where:
- * Array (
- * [0 DB row number] => 154
- * [1 Target ] => comment
- * [2 Time ] => 1534580897
- * [3 IP address ] => 102.177.147.***
- * [4 Country code ] => ZA
- * [5 Result ] => blocked
- * [6 AS number ] => AS328239
- * [7 Request ] => POST[80]:/wp-comments-post.php
- * [8 User agent ] => Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) ...
- * [9 HTTP headers ] => HTTP_ORIGIN=http://localhost,HTTP_X_FORWARDED_FOR=102.177.147.***
- * [10 $_POST data ] => comment=Hello.,author,email,url,comment_post_ID,comment_parent
- * )
- * And put a mark at "Target"
- * ¹¹: Passed in Whitelist
- * ¹²: Passed in Blacklist
- * ¹³: Passed not in list
- * ²¹: Blocked in Whitelist
- * ²²: Blocked in Blacklist
- * ²³: Blocked not in list
- */
- public function filter_logs( $logs ) {
- $settings = IP_Geo_Block::get_option();
-
- // White/Black list for back-end
- $white_backend = $settings['white_list'];
- $black_backend = $settings['black_list'];
-
- // White/Black list for front-end
- if ( $settings['public']['matching_rule'] < 0 ) {
- // Follow "Validation rule settings"
- $white_frontend = $white_backend;
- $black_frontend = $black_backend;
- } else {
- // Whitelist or Blacklist for "Public facing pages"
- $white_frontend = $settings['public']['white_list'];
- $black_frontend = $settings['public']['black_list'];
- }
-
- foreach ( $logs as $key => $log ) {
- // Passed or Blocked
- $mark = IP_Geo_Block::is_passed( $log[5] ) ? '¹' : '²';
-
- // Whitelisted, Blacklisted or N/A
- if ( 'public' === $log[1] ) {
- $mark .= IP_Geo_Block::is_listed( $log[4], $white_frontend ) ? '¹' : (
- IP_Geo_Block::is_listed( $log[4], $black_frontend ) ? '²' : '³' );
- } else {
- $mark .= IP_Geo_Block::is_listed( $log[4], $white_backend ) ? '¹' : (
- IP_Geo_Block::is_listed( $log[4], $black_backend ) ? '²' : '³' );
- }
-
- // Put a mark at "Target"
- $logs[ $key ][1] .= $mark;
- }
-
- return $logs;
- }
-
- /**
- * Register UI "Preset filters" at "Search in logs"
- *
- * @param array $filters An empty array by default.
- * @return array $filters The array of paired with 'title' and 'value'.
- */
- public function preset_filters( $filters = array() ) {
- return array(
- array( 'title' => '' . __( 'Passed in Whitelist', 'ip-geo-block' ), 'value' => '¹¹' ),
- array( 'title' => '' . __( 'Passed in Blacklist', 'ip-geo-block' ), 'value' => '¹²' ),
- array( 'title' => '' . __( 'Passed not in List', 'ip-geo-block' ), 'value' => '¹³' ),
- array( 'title' => '' . __( 'Blocked in Whitelist', 'ip-geo-block' ), 'value' => '²¹' ),
- array( 'title' => '' . __( 'Blocked in Blacklist', 'ip-geo-block' ), 'value' => '²²' ),
- array( 'title' => '' . __( 'Blocked not in List', 'ip-geo-block' ), 'value' => '²³' ),
- );
- }
-
- /**
- * Ajax callback function
- *
- * @link https://codex.wordpress.org/AJAX_in_Plugins
- * @link https://codex.wordpress.org/Function_Reference/check_ajax_referer
- * @link https://core.trac.wordpress.org/browser/trunk/wp-admin/admin-ajax.php
- */
- public function admin_ajax_callback() {
- require_once IP_GEO_BLOCK_PATH . 'admin/includes/class-admin-ajax.php';
-
- // Check request origin, nonce, capability.
- $this->check_admin_post( TRUE );
-
- // `$which` and `$cmd` should be restricted by whitelist in each function
- $settings = IP_Geo_Block::get_option();
- $which = isset( $_POST['which'] ) ? $_POST['which'] : NULL;
- $cmd = isset( $_POST['cmd' ] ) ? $_POST['cmd' ] : NULL;
-
- switch ( $cmd ) {
- case 'download':
- $res = IP_Geo_Block::get_instance();
- $res = $res->exec_update_db();
- break;
-
- case 'search': // Get geolocation by IP
- $res = array();
- foreach ( (array)$which as $cmd ) {
- $res[ $cmd ] = IP_Geo_Block_Admin_Ajax::search_ip( $cmd );
- }
- break;
-
- case 'scan-code': // Fetch providers to get country code
- $res = IP_Geo_Block_Admin_Ajax::scan_country( $which );
- break;
-
- case 'clear-statistics': // Set default values
- IP_Geo_Block_Logs::clear_stat();
- $res = array(
- 'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME,
- 'tab' => 'tab=1'
- );
- break;
-
- case 'clear-cache': // Delete cache of IP address
- IP_Geo_Block_API_Cache::clear_cache();
- $res = array(
- 'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME,
- 'tab' => 'tab=1'
- );
- break;
-
- case 'clear-logs': // Delete logs in MySQL DB
- IP_Geo_Block_Logs::clear_logs( $which );
- $res = array(
- 'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME,
- 'tab' => 'tab=4'
- );
- break;
-
- case 'export-logs':// Export logs from MySQL DB
- IP_Geo_Block_Admin_Ajax::export_logs( $which );
- break;
-
- case 'restore-logs': // Get logs from MySQL DB
- has_filter( $cmd = IP_Geo_Block::PLUGIN_NAME . '-logs' ) or add_filter( $cmd, array( $this, 'filter_logs' ) );
- $res = IP_Geo_Block_Admin_Ajax::restore_logs( $which );
- break;
-
- case 'live-start': // Restore live log
- has_filter( $cmd = IP_Geo_Block::PLUGIN_NAME . '-logs' ) or add_filter( $cmd, array( $this, 'filter_logs' ) );
- if ( is_wp_error( $res = IP_Geo_Block_Admin_Ajax::restore_live_log( $which, $settings ) ) )
- $res = array( 'error' => $res->get_error_message() );
- break;
-
- case 'live-pause': // Pause live log
- if ( ! is_wp_error( $res = IP_Geo_Block_Admin_Ajax::catch_live_log() ) )
- $res = array( 'data' => array() );
- else
- $res = array( 'error' => $res->get_error_message() );
- break;
-
- case 'live-stop': // Stop live log
- if ( ! is_wp_error( $res = IP_Geo_Block_Admin_Ajax::release_live_log() ) )
- $res = array( 'data' => array() );
- else
- $res = array( 'error' => $res->get_error_message() );
- break;
-
- case 'reset-live': // Reset data source of live log
- $res = IP_Geo_Block_Admin_Ajax::reset_live_log();
- break;
-
- case 'validate': // Validate settings
- IP_Geo_Block_Admin_Ajax::validate_settings( $this );
- break;
-
- case 'import-default': // Import initial settings
- $res = IP_Geo_Block_Admin_Ajax::settings_to_json( IP_Geo_Block::get_default() );
- break;
-
- case 'import-preferred': // Import preference
- $res = IP_Geo_Block_Admin_Ajax::preferred_to_json();
- break;
-
- case 'gmap-error': // Reset Google Maps API key
- if ( $settings['api_key']['GoogleMap'] === 'default' ) {
- $settings['api_key']['GoogleMap'] = NULL;
- IP_Geo_Block::update_option( $settings );
- $res = array(
- 'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME,
- 'tab' => 'tab=2'
- );
- }
- break;
-
- case 'generate-link': // Generate new link
- $res = array( 'link' => IP_Geo_Block_Util::generate_link( $this ) );
- break;
-
- case 'delete-link': // Delete existing link
- IP_Geo_Block_Util::delete_link( $this );
- break;
-
- case 'show-info': // Show system and debug information
- $res = IP_Geo_Block_Admin_Ajax::get_wp_info();
- break;
-
- case 'get-actions': // Get all the ajax/post actions
- $res = IP_Geo_Block_Util::get_registered_actions( TRUE );
- break;
-
- case 'export-cache': // Restore cache from database and format for DataTables
- IP_Geo_Block_Admin_Ajax::export_cache( $settings['anonymize'] );
- break;
-
- case 'restore-cache': // Restore cache from database and format for DataTables
- $res = IP_Geo_Block_Admin_Ajax::restore_cache( $settings['anonymize'] );
- break;
-
- case 'bulk-action-remove': // Delete specified IP addresses from cache
- $res = IP_Geo_Block_Logs::delete_cache_entry( $which['IP'] );
- break;
-
- case 'bulk-action-ip-erase':
- $res = IP_Geo_Block_Logs::delete_logs_entry( $which['IP'] );
- break;
-
- case 'bulk-action-ip-white':
- case 'bulk-action-ip-black':
- case 'bulk-action-as-white':
- case 'bulk-action-as-black':
- // Bulk actions for registration of settings
- $src = ( FALSE !== strpos( $cmd, '-ip-' ) ? 'IP' : 'AS' );
- $dst = ( FALSE !== strpos( $cmd, '-white' ) ? 'white_list' : 'black_list' );
-
- if ( empty( $which[ $src ] ) ) {
- $res = array( 'error' => sprintf( __( 'An error occurred while executing the ajax command `%s`.', 'ip-geo-block' ), $cmd ) );
- break;
- }
-
- foreach ( array_unique( (array)$which[ $src ] ) as $val ) {
- // replace anonymized IP address with CIDR (IPv4:256, IPv6:4096)
- $val = preg_replace(
- array( '/\.\*\*\*$/', '/:\w*\*\*\*$/', '/(::.*)::\/116$/' ),
- array( '.0/24', '::/116', '$1/116' ),
- trim( $val )
- );
- if ( ( filter_var( preg_replace( '/\/\d+$/', '', $val ), FILTER_VALIDATE_IP ) || preg_match( '/^AS\d+$/', $val ) ) &&
- ( FALSE === strpos( $settings['extra_ips'][ $dst ], $val ) ) ) {
- $settings['extra_ips'][ $dst ] .= "\n" . $val;
- }
- }
-
- if ( $this->is_network_admin && $settings['network_wide'] )
- $this->update_multisite_settings( $settings );
- else
- IP_Geo_Block::update_option( $settings );
-
- $res = array( 'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME );
- break;
-
- case 'restore-network': // Restore blocked per target in logs
- $res = IP_Geo_Block_Admin_Ajax::restore_network( $which, (int)$_POST['offset'], (int)$_POST['length'], FALSE );
- break;
-
- case 'find-admin':
- case 'find-plugins':
- case 'find-themes':
- // Get slug in blocked requests for exceptions
- $res = IP_Geo_Block_Admin_Ajax::find_exceptions( $cmd );
- break;
-
- case 'diag-tables': // Check database tables
- IP_Geo_Block_Logs::diag_tables() or IP_Geo_Block_Logs::create_tables();
- $res = array( 'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME );
- break;
- }
-
- if ( isset( $res ) ) // wp_send_json_{success,error}() @since 3.5.0
- wp_send_json( $res ); // @since 3.5.0
-
- die(); // End of ajax
- }
-
-}
\ No newline at end of file
diff --git a/wp/wp-content/plugins/ip-geo-block/admin/css/admin-icons.css b/wp/wp-content/plugins/ip-geo-block/admin/css/admin-icons.css
deleted file mode 100644
index 61110679..00000000
--- a/wp/wp-content/plugins/ip-geo-block/admin/css/admin-icons.css
+++ /dev/null
@@ -1,79 +0,0 @@
-/*! IP Geo Block admin icons
- * This package includes the following icon font.
- * IcoMoon - Free / Designer: Keyamoon / License: GPL / CC BY 4.0
- * Zondicons / Designer: Steve Schoger / License: CC BY 4.0
- * Material Icons / Designer: Google / License: Apache License 2.0
- */
-@font-face {
- font-family: 'icomoon';
- src: url('fonts/icomoon.eot?jihakz');
- src: url('fonts/icomoon.eot?jihakz#iefix') format('embedded-opentype'),
- url('fonts/icomoon.ttf?jihakz') format('truetype'),
- url('fonts/icomoon.woff?jihakz') format('woff'),
- url('fonts/icomoon.svg?jihakz#icomoon') format('svg');
- font-weight: normal;
- font-style: normal;
-}
-
-[class^="ip-geo-block-icon-"], [class*=" ip-geo-block-icon-"] {
- /* use !important to prevent issues with browser extensions that change fonts */
- font-family: 'icomoon' !important;
- speak: none;
- font-style: normal;
- font-weight: normal;
- font-variant: normal;
- text-transform: none;
- line-height: 1;
-
- /* Better Font Rendering =========== */
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-.ip-geo-block-icon-calc {
- margin-top: 0.2em !important;
-}
-.ip-geo-block-icon-calc:before {
- content: "\e901";
-}
-.ip-geo-block-icon-vpn_lock:before {
- content: "\e62f";
-}
-.ip-geo-block-icon-play:before {
- content: "\ea1c";
-}
-.ip-geo-block-icon-pause:before {
- content: "\ea1d";
-}
-.ip-geo-block-icon-stop:before {
- content: "\ea1e";
-}
-.ip-geo-block-icon-warning:before {
- content: "\e900";
-}
-.ip-geo-block-icon-happy:before {
- content: "\e9df";
-}
-.ip-geo-block-icon-grin2:before {
- content: "\e9ea";
-}
-.ip-geo-block-icon-cool:before {
- content: "\e9eb";
-}
-.ip-geo-block-icon-confused:before {
- content: "\e9f5";
-}
-.ip-geo-block-icon-confused2:before {
- content: "\e9f6";
-}
-.ip-geo-block-icon-crying:before {
- content: "\ea01";
-}
-
-/* Dashicons is the official icon font of the WordPress admin as of 3.8+. */
-#toplevel_page_ip-geo-block .dashicons-admin-generic:before {
- font-family: 'icomoon';
- content: "\e62f";
- font-size: 18px;
- margin-left: 2px;
-}
diff --git a/wp/wp-content/plugins/ip-geo-block/admin/css/admin-icons.min.css b/wp/wp-content/plugins/ip-geo-block/admin/css/admin-icons.min.css
deleted file mode 100644
index 6c9419fe..00000000
--- a/wp/wp-content/plugins/ip-geo-block/admin/css/admin-icons.min.css
+++ /dev/null
@@ -1,7 +0,0 @@
-/*! IP Geo Block admin icons
- * This package includes the following icon font.
- * IcoMoon - Free / Designer: Keyamoon / License: GPL / CC BY 4.0
- * Zondicons / Designer: Steve Schoger / License: CC BY 4.0
- * Material Icons / Designer: Google / License: Apache License 2.0
- */
-@font-face{font-family:icomoon;src:url(fonts/icomoon.eot?jihakz);src:url(fonts/icomoon.eot?jihakz#iefix) format('embedded-opentype'),url(fonts/icomoon.ttf?jihakz) format('truetype'),url(fonts/icomoon.woff?jihakz) format('woff'),url(fonts/icomoon.svg?jihakz#icomoon) format('svg');font-weight:400;font-style:normal}[class*=" ip-geo-block-icon-"],[class^=ip-geo-block-icon-]{font-family:icomoon!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ip-geo-block-icon-calc{margin-top:.2em!important}.ip-geo-block-icon-calc:before{content:"\e901"}.ip-geo-block-icon-vpn_lock:before{content:"\e62f"}.ip-geo-block-icon-play:before{content:"\ea1c"}.ip-geo-block-icon-pause:before{content:"\ea1d"}.ip-geo-block-icon-stop:before{content:"\ea1e"}.ip-geo-block-icon-warning:before{content:"\e900"}.ip-geo-block-icon-happy:before{content:"\e9df"}.ip-geo-block-icon-grin2:before{content:"\e9ea"}.ip-geo-block-icon-cool:before{content:"\e9eb"}.ip-geo-block-icon-confused:before{content:"\e9f5"}.ip-geo-block-icon-confused2:before{content:"\e9f6"}.ip-geo-block-icon-crying:before{content:"\ea01"}#toplevel_page_ip-geo-block .dashicons-admin-generic:before{font-family:icomoon;content:"\e62f";font-size:18px;margin-left:2px}
\ No newline at end of file
diff --git a/wp/wp-content/plugins/ip-geo-block/admin/css/admin.css b/wp/wp-content/plugins/ip-geo-block/admin/css/admin.css
deleted file mode 100644
index cf7a61d7..00000000
--- a/wp/wp-content/plugins/ip-geo-block/admin/css/admin.css
+++ /dev/null
@@ -1,1015 +0,0 @@
-/*!
- * Project: WordPress IP Geo Block
- * Copyright (c) 2013-2019 tokkonopapa (tokkonopapa@yahoo.com)
- * This software is released under the MIT License.
- */
-dfn {
- cursor: help;
- border-bottom: 1px dotted #888;
-}
-
-/* style legend and fieldset as panel */
-fieldset, legend {
- padding: 0;
- margin: 0;
- border: 0;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-fieldset {
- min-width: 0;
-}
-legend {
- display: block;
- line-height: inherit;
- width: 100%;
-}
-label {
- display: inline-block;
- max-width: 100%;
-}
-.panel {
- border-color: #888;
- border: 1px solid #e5e5e5;
- -webkit-box-shadow: 0 1px 1px rgba(0,0,0,.04);
- -moz-box-shadow: 0 1px 1px rgba(0,0,0,.04);
- box-shadow: 0 1px 1px rgba(0,0,0,.04);
- background: #f5f5f5;
-}
-.panel-heading {
- float: left !important;
- background: #fff;
-}
-.panel-default > .panel-heading {
- border-color: inherit;
-}
-.panel-body {
- width: 100%;
- padding: 0 1em;
- display: inline-block;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.panel-body:before,
-.panel-body:after {
- content: " ";
- display: table;
-}
-.panel-body:after {
- clear: both;
-}
-.ip-geo-block-navi-link {
- text-align: left;
-}
-.ip-geo-block-help-link {
- float: right;
- font-size: 90%;
- font-weight: normal;
-}
-.ip-geo-block-help-link a {
- box-shadow: none;
-}
-
-/* style legend and fieldset */
-fieldset label {
- vertical-align: text-middle;
-}
-fieldset input[type="checkbox"] {
- margin: 1px 2px 0;
-}
-fieldset.ip-geo-block-field {
-/* padding: 0 10px;*/
- margin: 1em 0;
-}
-fieldset.ip-geo-block-field h2,
-fieldset.ip-geo-block-field h3 {
- padding: 0;
- margin: 0;
- font-size: 14px !important;
-}
-fieldset.ip-geo-block-field h4 {
- margin: 0.75em 0 0.5em 0;
-}
-fieldset.ip-geo-block-field legend.panel-heading {
- padding: 10px;
-}
-
-fieldset.ip-geo-block-field .ip-geo-block-dropup,
-fieldset.ip-geo-block-field .ip-geo-block-dropdown {
- cursor: pointer;
- position: relative;
- padding-left: 1em;
-}
-fieldset.ip-geo-block-field .ip-geo-block-dropup:before,
-fieldset.ip-geo-block-field .ip-geo-block-dropdown:before {
- content: '';
- height: 0;
- width: 0;
- border: 0.4em solid transparent;
- position: absolute;
-}
-fieldset.ip-geo-block-field .ip-geo-block-dropup:before {
- border-left: 0.4em solid #555;
- left: 2px;
- top: 18%;
-}
-fieldset.ip-geo-block-field .ip-geo-block-dropdown:before {
- border-top: 0.4em solid #555;
- left: -2px;
- top: 38%;
-}
-fieldset.ip-geo-block-field .form-table .ip-geo-block-dropup,
-fieldset.ip-geo-block-field .form-table .ip-geo-block-dropdown {
- margin-top: 0.75em;
-}
-fieldset.ip-geo-block-field ul.ip-geo-block-dropup:before {
- top: 0.25em;
-}
-fieldset.ip-geo-block-field ul.ip-geo-block-dropdown:before {
- top: 0.5em;
-}
-fieldset.ip-geo-block-field table.form-table {
- margin: 0 0 0.5em;
- width: 100%;
-}
-
-/* Text */
-textarea.regular-text {
- width: 25em;
-}
-fieldset.ip-geo-block-field input.regular-text,
-fieldset.ip-geo-block-field textarea.regular-text {
- font-size: 95%;
-}
-
-/* Checkbox / Radio */
-p.ip-geo-block-navi-link input[type="checkbox"],
-fieldset.ip-geo-block-field input[type="checkbox"],
-fieldset.ip-geo-block-field input[type="radio"] {
- margin-right: 0.4em;
-}
-
-/* Plugins/Themes area, Geolocation API settings */
-input[id*="ip_geo_block_settings_rewrite_"] + label {
- margin-left: 0.25em;
-}
-input[id*="ip_geo_block_settings_providers"] + label {
- min-width: 7em;
-}
-
-/* Folding */
-.ip-geo-block-settings-folding {
- margin: 0.5em 0;
-}
-.ip-geo-block-settings-folding ul {
- margin-bottom: 0;
-}
-.ip-geo-block-settings-folding li {
- margin: 0.5em 0;
-}
-.folding-disable {
- pointer-events: none;
- opacity: 0.5;
-}
-.folding-inactive {
- opacity: 0.5;
- font-style:oblique !important;
-}
-
-/* Etc */
-.ip-geo-block-float li {
- display: inline-block;
- width: 18em;
- margin-top: 0;
-}
-.ip-geo-block-checked {
- list-style-type: disc;
-}
-.ip-geo-block-ip-addr {
- display: inline-block;
- padding-top: 5px;
-}
-.ip-geo-block-hide {
- display: none;
-}
-.ip-geo-block-sup {
- margin-left: 0.2em;
- display: inline-block;
-}
-.ip-geo-block-note {
- margin-top: 1em;
- list-style: disc inside;
-}
-.ip-geo-block-note li {
- text-indent: -1em;
- padding-left: 1em;
-}
-.ip-geo-block-border {
- border-top: inherit;
-}
-.ip-geo-block-notice {
- color: #dd3d36;
-}
-.ip-geo-block-title {
- width: 100px;
- display: inline-block;
-}
-.ip-geo-block-result {
- color: #2786C2;
- display: inline-block;
-}
-.ip-geo-block-primary {
- color: #fff !important;;
- background: #00838f !important;
- border-color: #00707a !important;
- text-shadow: none; /* for WordPress 3.7.21 */
-}
-.ip-geo-block-primary:hover {
- background-color: #00919e !important;
- border-color: #00525a !important;
-}
-ul#ip-geo-block-logs-preset {
- margin: 0.25em 0;
- max-width: 600px;
-}
-ul#ip-geo-block-logs-preset li {
- float: left;
- line-height: 1.5em;
- margin-right: 1em;
- min-width: 160px;
-}
-
-/* Loading image */
-.ip-geo-block-loading,
-#ip-geo-block-live-loading {
- height: 16px;
- width: 16px;
- background-size: 16px 16px;
- background-position: center center;
- background-repeat: no-repeat;
- margin-left: 1em;
- margin-top: 0.2em;
- display: inline-block;
- vertical-align: top;
-}
-.ip-geo-block-loading {
- background-image: url(data:image/gif;base64,R0lGODlhEAAQAPYCAKqqqsbGxlZWVsrKyvr6+ubm5tDQ0K6urmZmZmJiYuzs7IaGhvT09JycnLq6us7Ozurq6o6OjtbW1tra2vDw8CgoKCYmJvz8/NLS0kJCQlJSUqysrPLy8vb29pqamra2tm5ubujo6Kampvj4+IiIiMjIyEhISNzc3OLi4rKysj4+PlBQULi4uJKSkmRkZODg4KKiou7u7iQkJB4eHlpaWhISErCwsHh4eMDAwDIyMi4uLqSkpIKCgr6+vt7e3n5+fggICJCQkAwMDEpKSmBgYHZ2dhgYGBYWFnx8fF5eXk5OTiIiIjAwMIyMjISEhDQ0NJaWltTU1AQEBBwcHGpqaoqKiuTk5CoqKlhYWAoKCtjY2Hp6ehAQEJ6ensLCwkxMTJSUlCwsLAYGBnR0dDg4OFxcXLy8vKCgoA4ODsTExMzMzDw8PERERDY2NqioqHJycrS0tGhoaBQUFEZGRjo6OkBAQICAgHBwcFRUVCAgIGxsbP///wAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgACACwAAAAAEAAQAEAHjIACgoOEhYJsbTGGghcPGIJRbFNNhgQKCheDDkllDQYMHSc4MAcvhTB0aFliggQjmYNEFQ6LAh0+VoIwbFW1GGamhCgfUE5NbgMKtQYLc0a1gjsyR3E2IYwMFASDYDJvtRRWFIJ1TMq1ElqCICpetQoBEoInVCsAhhI2XhyEPUgIIG7waALlwAloCAMBACH5BAkKAAIALAEAAQAOAA4AAAeDgAKCEmBYYRVKJAaCjAcrVzIzRjVoTw2MKRk5Ww4KECkuWTWCE0Rrl4yCTow7bAupsBcCW19psKkjBEQaFLeMHBwINBy+ggoxVQkPxSMFMXBUMMUQPhRWVUU9tyFRLwQCA048cCcjIyFaJQYxjA8NEVBnAClmahCwEANwbjYBJwyMAgEAIfkECQoABQAsAQABAA4ADgAAB4OABYInO29DbC5QUYKMZiBfbCptTBUmIow4LgJBaTExZkVLFTAFKD8JB4yMQUZrBixUXaqqVFwkUG8Ys4wpQiZOWwy7ghBiRk08HcOqblUTy4wlLWbLBCMFCgBdurMjFMoFE24ADxAXFwwKITEEjD5mH2YBDxI+IdeqHCcGAxgv7IwCAQAh+QQJCgAAACwBAAEADgAOAAAHhYAAglYfTVQJSCITgowDVSAISQJKJgkpjA8LWyIGHBQBJCoZBwAQDU44jIxdTxoSAxEfqqpbFWApUCezjA5LWCJdI7uCClNXGyLCwxBHFl4HBcMAKVxfEx8Y0glZCxwlOCjDUkwPACElAygMghftAB6MClpRJygQFB0EuyMKBQUKDPQxCgQAIfkECQoAAAAsAQABAA4ADgAAB4SAAIIKahstTQ0OVoKMJzYeLVU8W29OXowvBztePh0dUTtxVD0AHDgHEoyMKWVvPj4sBqqqLUoiGDgQs4wBJmNqARe7gjEqXxgPwsMxbWw+UQzDAGY6LjEnusNjFmAEBVbRs00zc1EAHRAKHYw2CHIyO4wEHAwjgmJCZDC7F8psC7IEBQIAIfkECQoARwAsAQABAA4ADgAAB4OAR4IMPgMfNg4PCoKMEA84LCkAMB47GIwxBiUTEAQjKD0REQ9HBD4YIYyMATwtBRQnqaqMG0UOEC8ds4wYIEEQBbuMHC4gMYvCRxw0CAwcF8kBGj8EHdDCJCYiRxfXsw0qCROqRDYQECw3ORkpqjpAQjVGMxYrB7MPC0MyFQItEowCAQAh+QQJCgACACwBAAEADgAOAAAHgIACghcUVhIYEigMgowjEC8nUQ8BOGkojAQxITEdAhcxEh9wPoIMFCOMjBMAKTEXHaipjGldDxcEsqkvUAe5sh1NLb6pHTxNbGK9vlE3DU5ZLsNnIA4GbTVVuQcJdpdnS0Z3LAoxXhF4LjiMMBl5FjptKiZ6ZrJRLUkqbCAwJ4yBACH5BAUKAAEALAEAAQAOAA4AAAd/gAGCARcjHDExHASDjAQdHAoFLy8Ugw2MgiMKWhIKAQ9MYpiCEA8YHQtZCaOCJ14vX2g2rAEKZgMyNRC0BCksFUa7rCMANgIzH7QvZw4tMmO0DlAPUV9hHqNeVTC7G2tkTmkUHA8iSFUGgzZlGSYaNC4gTWqYEzA3SQhVH1aDgQA7);
-}
-
-/* Google Map infomation window */
-#ip-geo-block-map {
- height: 400px;
- margin: 1em auto;
-}
-#ip-geo-block-apis div.nav-tab-wrapper {
- padding-top: 0;
- margin-bottom: 1em;
-}
-#ip-geo-block-geoinfo {
- white-space: normal;
- word-wrap: break-word;
- word-break: break-all;
-}
-#ip-geo-block-geoinfo ul {
- margin-top: 0;
- margin-left: 1em;
-}
-.gm-style-iw {
- width: 18em;
- height: auto !important;
- height: 100%;
- min-height: 100%:
-}
-.gm-style-iw ul {
- margin: 0.1em;
-}
-.gm-style-iw li {
- margin: 0.2em;
-}
-
-/* SVG in google chart */
-svg a {
- cursor: pointer;
-}
-svg a:hover > text {
- fill: #0096dd;
-}
-svg a > text {
- fill: #0073aa;
- text-decoration: underline;
-}
-
-/* table */
-table.ip-geo-block-statistics-table {
- float: right;
-}
-table.ip-geo-block-statistics-table th,
-table.ip-geo-block-statistics-table td {
- width: 12em;
- margin: 0;
- padding: 0.2em;
- text-align: right;
- line-height: 1.5em;
- word-wrap: break-word;
-}
-table.ip-geo-block-statistics-table tr:nth-child(even) {
- background-color: #eee;
-}
-table.ip-geo-block-statistics-table tr:nth-child(odd) {
-}
-table.ip-geo-block-table {
- margin: 1em 0;
- width: 100%;
- white-space: normal;
- word-wrap: break-word;
- word-break: break-all;
-}
-table.ip-geo-block-table td:first-child {
- min-width: 4.3em;
- max-width: 5.0em;
-}
-
-/* Whois */
-@media screen and (max-width:782px) {
- #ip-geo-block-whois .panel-body {
- padding: 0 0.5em;
- }
-}
-
-/* Scan the country code */
-#ip-geo-block-scan-code {
- vertical-align: middle;
-}
-#ip-geo-block-code-list {
- display: none;
- margin-bottom: 0;
-}
-
-/* Google Chart */
-#ip-geo-block-chart-countries {
- height: 200px;
-}
-#ip-geo-block-chart-daily {
- height: 240px;
-}
-#ip_geo_block_settings_validation_mimetype + label {
- padding-top: 0.25em;
-}
-#ip_geo_block_settings_validation_mimetype + label + ul {
- margin-top: 0.7em;
-}
-#ip_geo_block_settings_create_user {
- margin-bottom: 0.5em;
-}
-#ip-geo-block-toggle-sections,
-#ip-geo-block-back-to-top a {
- box-shadow: none;
-}
-#ip-geo-block-wp-info textarea {
- margin-top: 0.5em;
- overflow: auto;
- width: 100%;
- word-wrap: normal;
- word-break: normal;
- white-space: pre;
-}
-#ip-geo-block-back-to-top {
- margin:0;
- text-align:right;
-}
-#ip-geo-block-open-new,
-#ip-geo-block-live-update {
- margin-left: 1em;
-}
-
-/* Top menu link */
-.ip-geo-block-menu-link {
- font-size: 13px !important;
-}
-
-/* Icons */
-dfn ~ .ip-geo-block-icon {
- margin-left: 0.4em;
-}
-.ip-geo-block-icon {
- position: relative;
- cursor: pointer;
- outline: none;
- box-shadow: none;
- text-decoration: none;
- background-color: transparent;
-}
-.ip-geo-block-icon:active {
- top: 1px;
-}
-.ip-geo-block-icon span {
- height: 16px;
- width: 16px;
- margin: 0;
- border: none;
- display: inline-block;
- vertical-align: middle;
- background-size: 16px 16px;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.ip-geo-block-icon-cycle span {
- background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAh1BMVEUAda2otLp+rsSHprWHr8IBd7EpfKRGhaNajqeUqrRymKuKoq5yo7prlKgAcqoVe6w8gqQmgq5Tj6wIdqsVdKIshrEMea1Uhp+Anqw0hawDdq4gfKhljqE7hqoLdKYbgbM4jLQygKUGeK8CdawQd6gVeKcad6NKkrSerrZAj7UAc6sAc6rc3NySrVGQAAAALXRSTlP//////////////////////////////////////////////////////////wCl7wv9AAACOklEQVR4Ae2W15rzKgxF9xTZzhTX9B7S/gN6/9ebYqzzGZsw/S7LV3FZgCSIwD/kQ8FVcBU8xatZUczy8luC/ABNOn0DSHEsvyZ4PgLatNCYR3efFxyhTQ8g+qQgJxgv2JefERzJXATRh4LHOUwAHD4S7OGEztRJaN86hAUxtaNWDUf/bRdDBbQMWVDAO8jn89WUhag1MeyCAh6hHofyrliLgZKggDMYgzF3eVAwFq0uCZq5KY0TezjIHDDzC0qqmkwe2ctGDOQVLMkgu+F3/rGXwb4xIPcJ6P3JgkM8wFjmfcFAWfeKQywaAz33BJVuHsUcAt09gVbuLDThAJkdR687ggLmf4gDJLIGV7BydtB8yn3u+fbtuj/LS7G9wZAd1AKK+yxJ1x+aBmibTtgCcEHGHsh0wdbOgNLek4L7lI5BigY8nWuZUQ3qGEXes9JzOKGJztPaGtLslu3lIXJirdxCWkASHGDTMqg7V1DKPplygDG61YJukLHjEErGSXqCSos6xNSOgzP3BDmsQBcchNwkoV8oiNnPA78zIefUgCdJeGIfE7LmFWXsFTCFdzTJ/RlfEMRiSGnFXXbkC7AIeqcKDu4ynseozeouKJiSEYBDwkJyIC1nRUjgblkNWp/e/1vXc2gjoAoLksYgjrrFMi0oDgjEEIDij1scBXMJSH6DAj6RNl7o8MkuLak8Co15/Pk+MRmT0xilQJV/sdWNKg2kTaeroudvNNsDjmejYjSL+e6v2/2r4Cp4BXNajr0H7hRfAAAAAElFTkSuQmCC);
-}
-.ip-geo-block-icon-lock span {
- background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3Ny3y9Zzq8dRmb7M1dlXnsIFdK0AcawAcqwphrYAcKvZ29wAb6oJd680jrqlw9MBcqxmo8MUfbJLl75eoMI7kbzX2ttqp8VSmL1YnL8NeK+Tu89DlL1ImMEOebBNmL4OkqMoAAAAAXRSTlMAQObYZgAAAPlJREFUeAG9kAWyhTAQBIPOsCzufv9TPnf4Ll0CSbpmxXwNy3Yc23rz2fV8kPA99433AIQIiGDTCD0lojiOQPXCDSFJIbF16CMWItkQMkF+inZzSLYhFKLl+a9UKTZaqJTZJYtarZuo40chrv9CqJTN+behVi+Cm7RdDgRld6AMgLxrE/dxBz0BEjwBEmD/uIsWPAOAF9A+CE56ufSryr8oqfOYcBbQJ8YkES7COkFOYzTypqCDOTDo2wljaEw4vp1APYyWKd8WMBozylvCpcvmXeHQ5fCegHia4s1FgZcIVeVFeFx1M4MvYG4eBHdYWufC+addBtf8E3vdjBNhWnVQqAAAAABJRU5ErkJggg==);
-}
-.ip-geo-block-icon-unlock span {
- background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3NyzydRzq8dRmb7I09hYnsEFdK0AcawAcqzP1toqhrYAcKvZ29wAb6oMeK8zjbqrxtQBcazBz9Zko8MVfbLF0thMmL07kbtpp8WjwtJSmL1YnL+Tu89DlL1JmMEPebBFV++UAAAAAXRSTlMAQObYZgAAAONJREFUeAG9kAWChDAMAIMmJaTFXf7/ynXflvMbnE5j8DU8Pwh8D1yEUYxEGEchWFEJEjEflESBhTQSQm2MRpIotQhZTmgKgMIg5ZlFKBmrGg7UFXJpEQKW8qIKN7YeikJdBJI2BTtXwfyx0L3XoPphvBEliNU49OoxqEa6g4cTST/OYshvi3hV8+FxSNfluG3jqxG8C6h7gF6jU+AODnTsFGSCA5O4I8wpQDq7I5CUAKWQW+AZYOYtoQPoGDeECWDaioBmWQxeBduoWURso+5WpBdw7R4ENTVDcGE435tJwT+xB+vMEnZRNB0YAAAAAElFTkSuQmCC);
-}
-.ip-geo-block-icon-find span {
- background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3NzS19rD0NWHtMpGk7kYfbAGda0Req+WtcTT1temwM4AcasAcqwAc6wAcKydvMt1pr8Ab6pqpcLX2doggrKoxdNYm7yzw8u/y9HO1tkKdq4th7Td3t6DrcLL0taxyNPGe/YhAAAAAXRSTlMAQObYZgAAARVJREFUeAGtkkeiwyAMRP2xDfxoRjElvd3/lOkNUlZ5u0GPruan/Bnz96Xadr21rvP/7+ujXsAjom78rj4ApCoERIipqfGB1H7wPmYhw1DXjZI6nOel1oJhVAmdUP0tTEDkVC4AYvqIbaDOCqFV6vwRF0tIeYoo6J/X7ICuPAJl9ZynwiIfB5DXxZlRChulbh8xZci0EHZK3TziJFDL504rEOZ+iR5cVj82DoS7XtSshLJpKqaB0Dg3ZjcsQWKaKiF1gVQlITwh/bw2pgKeEeURhE29yKSzUFF03p1V7Wqj2Y7GfrY9X/NirJsPxKsxfBLSSs5GmH8yjAWPSNd8Yoez4f4/G1nIsksqFtGK1i9e39o0P+EAqaoRLlQ+r94AAAAASUVORK5CYII=);
-}
-span.ip-geo-block-icon-alert,
-.ip-geo-block-icon-alert span {
- background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAkFBMVEXc3Nzc2trWl5DHRDTFOyvOgXfc1tXCLBrEMiHEMyLNcmfaxMLDMSDDLx7bu7jRiYHDLhzDMB/LX1PaxsTDLh3YtrHMY1bWmpPJVknSjYXUkYnZuLTMZVnENCPWlI3QhXzENiXXrqrDLRzXsa3Oal7Pe3Hc2NjVn5nNbmPayMbbwb7ay8rUj4fc09Lbw8Db0dDBbRUDAAAAAXRSTlMAQObYZgAAAPVJREFUeAG9ktXWwyAQBonC12brFvff5f2frr4nBredK2DnTFS8Gst2XM8XZmypIGeWcT4PFABaGIXlClfWG1NiC4Ubu705oKRcY32wTAHl2MdTYEqEK8hIiHgHSnSJeaogMyEWO4BijZCvwII2MS9UJ2BXTh+hQidoEttboBOwq3WBnkCNpQlA2iyAhol2hRu71n97p4fw0Z9/ugoPHCfFA+o/iLfCkyBglRJdICBas7uuey+R56fF14wNanj+/QjwY3aX23cBFn6EiHmHNT/ICYxystv/wJy4UHWGlN2cuPB72tFqAq3dP/Hk3zs0E5LZVryGC/hqGNnUa0SVAAAAAElFTkSuQmCC);
- vertical-align: bottom;
-}
-
-table.form-table th .ip-geo-block-cycle span {
- vertical-align: text-bottom;
-}
-
-/* Option list */
-.ip-geo-block-list {
- margin-top: 0;
- margin-bottom: 0.7em;
-}
-@media screen and (min-width:782px) {
- ul.ip-geo-block-list .code {
- width: 15em;
- }
-}
-
-/* Exceptions */
-.ip-geo-block-list-exceptions label {
- display: inline-block;
-}
-.ip-geo-block-list-exceptions dfn {
- border: none;
-}
-.ip-geo-block-list-exceptions span.dashicons {
- font-size: 14px;
-}
-.ip-geo-block-list-exceptions a.ip-geo-block-icon {
- margin-left: 0.3em;
- outline: none;
- box-shadow: none;
- text-decoration: none;
- background-color: transparent;
-}
-
-/* Description */
-.form-table td p.ip-geo-block-desc,
-.form-table td p.ip-geo-block-find-desc {
- color: #666;
- font-size: 13px !important;
- margin: 4px 0 0.5em 0.5em;
-}
-.ip-geo-block-find-desc {
- display: none;
-}
-
-/* Action for admin post */
-.ip-geo-block-admin-post {
- color: #c43322;
- margin-left: 0.25em;
-}
-.ip-geo-block-warn {
- color: #c43322;
- font-weight: bold;
-}
-
-/* Badly-behaved bots and crawlers */
-input#ip_geo_block_settings_behavior_view,
-input#ip_geo_block_settings_behavior_time {
- width: 3.5em;
-}
-
-/* Statistics */
-.ip-geo-block-top-list {
- display: inline-table;
- list-style-position: outside;
- margin: 0 2em 0.5em 1.75em;
-}
-.ip-geo-block-top-list h4 {
- margin: 1em 0;
-}
-.ip-geo-block-top-list li code {
- background: none;
-}
-
-/* Embeded data for network site list */
-.ip-geo-block-network {
- margin-bottom: 1em;
-}
-
-/*------------------------------------------------------------
- * multi column for Site List
- * https://caniuse.com/#search=flexbox
- *------------------------------------------------------------*/
-.ip-geo-block-container {
- margin: 0 auto;
- padding: 0 1em;
- position: relative;
- width: 100%;
-}
-.ip-geo-block-row {
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- align-items: stretch; /* baseline */
- padding: 0;
- width: 100%;
-}
-.ip-geo-block-row .ip-geo-block-column {
- display: block;
- flex: 1 1 auto;
- align-self: flex-start;
- margin-left: 0;
- max-width: 100%;
- width: 100%;
-}
-.ip-geo-block-row .ip-geo-block-column.column-20 {
- flex: 0 0 20%;
- max-width: 20%;
-}
-.ip-geo-block-row .ip-geo-block-column.column-25 {
- flex: 0 0 25%;
- max-width: 25%;
-}
-.ip-geo-block-row .ip-geo-block-column.column-33 {
- flex: 0 0 33.3333%;
- max-width: 33.3333%;
-}
-.ip-geo-block-row .ip-geo-block-column.column-50 {
- flex: 0 0 50%;
- max-width: 50%;
-}
-@media (min-width: 40rem) {
- .ip-geo-block-row {
- flex-direction: row;
- margin-left: -2em;
- width: calc(100% + 2em);
- }
- .ip-geo-block-row .ip-geo-block-column {
- margin-bottom: inherit;
- padding: 0 1em;
- }
-}
-
-/*------------------------------------------------------------
- * Customizing based on jquery.dataTables.css
- *------------------------------------------------------------*/
-table.ip-geo-block-dataTable {
- clear: none !important;
-}
-table.ip-geo-block-dataTable th,
-table.ip-geo-block-dataTable td {
- text-align: right;
-}
-table.ip-geo-block-dataTable th:nth-child(n+2),
-table.ip-geo-block-dataTable td:nth-child(n+2) {
- padding-left: 0 !important;
-}
-table.ip-geo-block-dataTable th {
- white-space: nowrap;
-}
-table.ip-geo-block-dataTable > thead > tr {
- line-height: 1.8em;
-}
-table.ip-geo-block-dataTable > tbody > tr {
- cursor: pointer;
-}
-table.ip-geo-block-dataTable > thead > tr > th,
-table.ip-geo-block-dataTable > thead > tr > td,
-table.ip-geo-block-dataTable.no-footer {
- border-bottom: 1px solid #ddd;
-}
-table.ip-geo-block-dataTable thead th,
-table.ip-geo-block-dataTable thead td {
- padding: 10px 16px;
-}
-/* country code */
-#ip-geo-block-statistics-cache td:nth-child(3),
-#ip-geo-block-validation-logs td:nth-child(4) {
- min-width: 1.6em;
-}
-
-/* Scroll bar */
-div[class*="ip-geo-block"] .dataTables_wrapper.no-footer .dataTables_scrollBody {
- border-bottom: 1px solid #ddd;
-}
-
-/* Size of column */
-table.ip-geo-block-dataTable.nowrap td,
-table.ip-geo-block-dataTable > tbody > tr > td span {
- white-space: normal !important;
- word-wrap: break-word !important;
- word-break: break-all !important;
-}
-table.ip-geo-block-dataTable > tbody > tr > td span {
- display: inline-block;
-}
-
-/* Checkbox */
-.ip-geo-block-settings-folding input[type="checkbox"] {
- margin-right: 0.5em;
-}
-table.ip-geo-block-dataTable input[type="checkbox"] {
- margin: 0;
- max-height: 16px;
- max-width: 16px;
- vertical-align: middle;
-}
-table.ip-geo-block-dataTable > thead > tr > th:first-child,
-table.ip-geo-block-dataTable > tbody > tr > td:first-child {
- padding: 8px 4px 8px 1.4em;
- text-align: left;
-}
-
-/* No data available in table */
-table.ip-geo-block-dataTable > tbody > tr > td.dataTables_empty,
-table.collapsed > tbody > tr > td.dataTables_empty:first-child::before {
- border: none;
- text-align: center;
-}
-
-/* Checkbox column */
-table.ip-geo-block-dataTable thead > tr > th:first-child.sorting_asc {
- background-image: none !important;
-}
-table.ip-geo-block-dataTable.display tbody tr.even > .sorting_1,
-table.ip-geo-block-dataTable.display tbody tr.odd > .sorting_1,
-table.ip-geo-block-dataTable.display tbody tr:hover > .sorting_1 {
- background-color: inherit !important;
-}
-
-/* Collapsed */
-table.ip-geo-block-dataTable.collapsed > tbody > tr > td:first-child {
- padding: 8px 4px 8px 8px !important;
-}
-table.collapsed > tbody > tr > td:first-child::before,
-table.collapsed > tbody > tr.parent > td:first-child::before {
- content: '';
- height: 0;
- width: 0;
- display: inline-block;
- border-radius: 0;
- border: 5px solid transparent;
- box-shadow: none;
- position: relative;
- background-color: transparent;
-}
-table.collapsed > tbody > tr > td:first-child::before {
- border-left: 5px solid #555;
- top: 1px;
- left: -2px;
-}
-table.collapsed > tbody > tr.parent > td:first-child::before {
- border-top: 5px solid #555;
- top: 4px;
- left: -4px;
-}
-table.collapsed > tbody > tr.child > td:first-child::before {
- border: none;
-}
-table.collapsed > tbody > tr.child > td.child > ul li {
- border: none;
- padding: 0;
- margin: 0;
- line-height: 1.8em;
-}
-table.collapsed > tbody > tr.child > td.child > ul li span.dtr-title,
-table.collapsed > tbody > tr.child > td.child > ul li span.dtr-data {
- font-size: 13px !important;
- display: block;
- white-space: normal;
- word-wrap: break-word;
- word-break: break-all;
-}
-table.collapsed > tbody > tr.child > td.child > ul li span.dtr-data {
- margin-left: 1.25em;
- margin-right: 0.3em;
-}
-
-/* Length menu */
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_length {
- padding-top: 0.15em;
- margin: 0.5em 0 0 0.3em;
- position: relative;
- display: inline-block;
-}
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_length:after {
- content: '';
- width: 6px;
- height: 6px;
- border: 0px;
- border-bottom: solid 2px #999;
- border-right: solid 2px #999;
- -ms-transform: rotate(45deg);
- -webkit-transform: rotate(45deg);
- transform: rotate(45deg);
- position: absolute;
- top: 50%;
- right: 10px;
- margin-top: -4px;
-}
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_length select {
- padding-top: 0;
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
- font-size: 13px !important;
- line-height: 1.4em;
- width: 100%;
- height: 2.05em !important;
- background: transparent;
- position: relative;
- z-index: 1;
- padding: 0.125em 1.5em 0.125em 0.25em;
- border: 1px solid #ddd;
- border-radius: 4px;
- box-shadow: none;
-}
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_length select::-ms-expand {
- display: none;
-}
-
-/* Pagenation */
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate {
- float: none;
- text-align: center;
- margin-bottom: 1em;
- margin-top: 0 !important;
-}
-@media screen and (min-width:640px) {
- div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_length {
- margin: 0.5em 0 0 0.6em;
- }
- div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate {
- position: relative;
- left: -2.25em;
- }
-}
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate span.ellipsis,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button:hover,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button:active,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.current,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:hover,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:active,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:hover,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:active {
- min-width: 2em;
- background: inherit;
- border-color: #ddd;
- border-radius: 0;
- border-image: none;
- border-style: solid;
- border-width: 1px 1px 1px 0;
- box-shadow: none;
- margin: 0.5em 0 0 0;
- padding: 0.25em 0;
- display: inline-block;
- text-decoration: none;
-}
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate > a.paginate_button:first-child,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate:hover > a.paginate_button:first-child,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate:active > a.paginate_button:first-child {
- border-left-width: 1px;
- border-bottom-left-radius: 4px;
- border-top-left-radius: 4px;
-}
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate > a.paginate_button:last-child,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate:hover > a.paginate_button:last-child,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate:active > a.paginate_button:last-child {
- border-bottom-right-radius: 4px;
- border-top-right-radius: 4px;
-}
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button {
- color: #0073aa !important;
-}
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button:hover {
- color: #0096dd !important;
- background-color: #fff;
-}
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate span.ellipsis,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:hover,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:active {
- cursor: default;
- color: #999 !important;
- background-color: transparent;
-}
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.current,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:hover,
-div[class*="ip-geo-block"] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:active {
- cursor: default;
- color: #444 !important;
- background-color: #fff !important;
-}
-
-/* Alignment of table */
-#ip-geo-block-1 #ip-geo-block-section-2 .panel-body,
-#ip-geo-block-4 #ip-geo-block-section-0 .panel-body {
- padding: 0;
-}
-#ip-geo-block-1 #ip-geo-block-section-2 table.form-table,
-#ip-geo-block-4 #ip-geo-block-section-0 table.form-table {
- margin-left: 1em;
- max-width: 95%;
-}
-
-/* Select target / Period to extract */
-#ip-geo-block-select-target,
-#ip-geo-block-select-layout,
-#ip-geo-block-select-duration {
- margin: 0;
-}
-#ip-geo-block-select-target li,
-#ip-geo-block-select-layout li,
-#ip-geo-block-select-duration li {
- float: left;
- margin-right: 1.5em;
-}
-#ip-geo-block-select-target li label,
-#ip-geo-block-select-duration li label {
- cursor: pointer;
-}
-
-/* Filter */
-#ip_geo_block_settings_search_filter {
- width: 16em;
- padding-top: 3px;
-}
-
-/* Transition for new row */
-table.ip-geo-block-dataTable.display tbody tr.ip-geo-block-passed {
- background-color: #edf6ff !important;
-}
-table.ip-geo-block-dataTable.display tbody tr.ip-geo-block-blocked {
- background-color: #ffefef !important;
-}
-.ip-geo-block-new-passed {
- animation: ip-geo-block-flash-passed 1s ease-out 0s 1 normal both running;
-}
-.ip-geo-block-new-blocked {
- animation: ip-geo-block-flash-blocked 1s ease-out 0s 1 normal both running;
-}
-@keyframes ip-geo-block-flash-passed {
- 0% { background-color: #ffd700; }
- 100% { background-color: #edf6ff; }
-}
-@keyframes ip-geo-block-flash-blocked {
- 0% { background-color: #ffd700; }
- 100% { background-color: #ffefef; }
-}
-
-/* Mark.js */
-mark {
- padding: 0;
- background: #ffd700; // Gold
-}
-
-/* Live update log */
-#ip-geo-block-live-log {
- margin: 0;
-}
-#ip-geo-block-live-log li {
- float: left;
- margin-right: 3em;
-}
-#ip-geo-block-live-log li:last-child {
- margin-right: 0;
-}
-#ip-geo-block-live-log li input[type=radio] {
- visibility: hidden;
- position: absolute;
-}
-#ip-geo-block-live-log li input[type=radio] + label {
- display:inline-block;
- margin:-2px;
- padding: 4px 12px;
- margin-bottom: 0;
- font-size: 14px;
- line-height: 20px;
- color: #333;
- text-align: center;
- text-shadow: 0 1px 1px rgba(255,255,255,0.75);
- vertical-align: middle;
- cursor: pointer;
- background-color: #f5f5f5;
- background-image: -moz-linear-gradient(top,#fff,#e6e6e6);
- background-image: -webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));
- background-image: -webkit-linear-gradient(top,#fff,#e6e6e6);
- background-image: -o-linear-gradient(top,#fff,#e6e6e6);
- background-image: linear-gradient(to bottom,#fff,#e6e6e6);
- background-repeat: repeat-x;
- border: 1px solid #ccc;
- border-color: #e6e6e6 #e6e6e6 #bfbfbf;
- border-color: rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);
- border-bottom-color: #b3b3b3;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
- -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
- -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
- box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
-}
-#ip-geo-block-live-log li input[type=radio]:checked + label {
- background-image: none;
- outline: 0;
- -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
- -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
- box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
- background-color: #e0e0e0;
-}
-
-/*----------------------------------------------------------------------
- * Timer animation based on https://codepen.io/paulobrien/pen/joptI
- *----------------------------------------------------------------------*/
-.ip-geo-block-live-timer {
- height: 1em;
- width: 1em;
- margin: 0;
- position: relative;
- top: 0;
- left: 0;
-}
-.ip-geo-block-live-timer:before {
- content: "";
- display: block;
- height: 1em;
- width: 1em;
- background: #0073aa;
- border-radius: 50%;
- position: absolute;
- top: 0;
- left: 0;
-}
-.ip-geo-block-live-timer:after {
- display: none
-}
-.ip-geo-block-live-timer > div {
- position: absolute;
- width: 1em;
- height: 1em;
- clip: rect(0, 1em, 1em, .5em);
-}
-.ip-geo-block-live-timer > div:before {
- content: " ";
- position: absolute;
- width: 1em;
- height: 1em;
- border-radius: .5em;
- clip: rect(0, .5em, 1em, 0);
- background-color: #f1f1f1;
- transform: rotate(0deg);
-}
-.ip-geo-block-live-timer > div:first-child:before {
- animation: 30s spin-timer linear forwards;
-}
-.ip-geo-block-live-timer > div:last-child {
- transform: rotate(180deg);
-}
-.ip-geo-block-live-timer > div:last-child:before {
- /* older webkit seems buggy with zero so use 0.00001 if you notice something strange */
- transform: rotate(0deg);
- animation: 30s spin-timer linear 30s forwards;
-}
-@keyframes spin-timer {
- 0% {transform: rotate( 0deg);}
- 100% {transform: rotate(180deg);}
-}
-
-/* sub items in settings */
-.ip-geo-block-subitem {
- margin-left: 1.7em
-}
-.ip-geo-block-subitem:before {
- content: "\00bb"; /* » */
- position: absolute;
- left: 2em;
-}
-.ip-geo-block-subitem dfn {
- vertical-align: middle;
-}
-.ip-geo-block-subitem-parent th,
-.ip-geo-block-subitem-parent td {
- padding-top: 0;
-}
-
-/* placeholder */
-:placeholder-shown { color: #888; }
-::-webkit-input-placeholder { color: #888; } /* Google Chrome, Safari, Opera 15+, Android, iOS */
-:-moz-placeholder { color: #888; opacity: 1; } /* Firefox 18- */
-::-moz-placeholder { color: #888; opacity: 1; } /* Firefox 19+ */
-:-ms-input-placeholder { color: #888; } /* IE 10+ */
diff --git a/wp/wp-content/plugins/ip-geo-block/admin/css/admin.min.css b/wp/wp-content/plugins/ip-geo-block/admin/css/admin.min.css
deleted file mode 100644
index 50795951..00000000
--- a/wp/wp-content/plugins/ip-geo-block/admin/css/admin.min.css
+++ /dev/null
@@ -1,6 +0,0 @@
-/*!
- * Project: WordPress IP Geo Block
- * Copyright (c) 2013-2019 tokkonopapa (tokkonopapa@yahoo.com)
- * This software is released under the MIT License.
- */
-dfn{cursor:help;border-bottom:1px dotted #888}fieldset,legend{padding:0;margin:0;border:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}fieldset{min-width:0}legend{display:block;line-height:inherit;width:100%}label{display:inline-block;max-width:100%}.panel{border-color:#888;border:1px solid #e5e5e5;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.04);-moz-box-shadow:0 1px 1px rgba(0,0,0,.04);box-shadow:0 1px 1px rgba(0,0,0,.04);background:#f5f5f5}.panel-heading{float:left!important;background:#fff}.panel-default>.panel-heading{border-color:inherit}.panel-body{width:100%;padding:0 1em;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.panel-body:after,.panel-body:before{content:" ";display:table}.panel-body:after{clear:both}.ip-geo-block-navi-link{text-align:left}.ip-geo-block-help-link{float:right;font-size:90%;font-weight:400}.ip-geo-block-help-link a{box-shadow:none}fieldset label{vertical-align:text-middle}fieldset input[type=checkbox]{margin:1px 2px 0}fieldset.ip-geo-block-field{margin:1em 0}fieldset.ip-geo-block-field h2,fieldset.ip-geo-block-field h3{padding:0;margin:0;font-size:14px!important}fieldset.ip-geo-block-field h4{margin:.75em 0 .5em 0}fieldset.ip-geo-block-field legend.panel-heading{padding:10px}fieldset.ip-geo-block-field .ip-geo-block-dropdown,fieldset.ip-geo-block-field .ip-geo-block-dropup{cursor:pointer;position:relative;padding-left:1em}fieldset.ip-geo-block-field .ip-geo-block-dropdown:before,fieldset.ip-geo-block-field .ip-geo-block-dropup:before{content:'';height:0;width:0;border:.4em solid transparent;position:absolute}fieldset.ip-geo-block-field .ip-geo-block-dropup:before{border-left:.4em solid #555;left:2px;top:18%}fieldset.ip-geo-block-field .ip-geo-block-dropdown:before{border-top:.4em solid #555;left:-2px;top:38%}fieldset.ip-geo-block-field .form-table .ip-geo-block-dropdown,fieldset.ip-geo-block-field .form-table .ip-geo-block-dropup{margin-top:.75em}fieldset.ip-geo-block-field ul.ip-geo-block-dropup:before{top:.25em}fieldset.ip-geo-block-field ul.ip-geo-block-dropdown:before{top:.5em}fieldset.ip-geo-block-field table.form-table{margin:0 0 .5em;width:100%}textarea.regular-text{width:25em}fieldset.ip-geo-block-field input.regular-text,fieldset.ip-geo-block-field textarea.regular-text{font-size:95%}fieldset.ip-geo-block-field input[type=checkbox],fieldset.ip-geo-block-field input[type=radio],p.ip-geo-block-navi-link input[type=checkbox]{margin-right:.4em}input[id*=ip_geo_block_settings_rewrite_]+label{margin-left:.25em}input[id*=ip_geo_block_settings_providers]+label{min-width:7em}.ip-geo-block-settings-folding{margin:.5em 0}.ip-geo-block-settings-folding ul{margin-bottom:0}.ip-geo-block-settings-folding li{margin:.5em 0}.folding-disable{pointer-events:none;opacity:.5}.folding-inactive{opacity:.5;font-style:oblique!important}.ip-geo-block-float li{display:inline-block;width:18em;margin-top:0}.ip-geo-block-checked{list-style-type:disc}.ip-geo-block-ip-addr{display:inline-block;padding-top:5px}.ip-geo-block-hide{display:none}.ip-geo-block-sup{margin-left:.2em;display:inline-block}.ip-geo-block-note{margin-top:1em;list-style:disc inside}.ip-geo-block-note li{text-indent:-1em;padding-left:1em}.ip-geo-block-border{border-top:inherit}.ip-geo-block-notice{color:#dd3d36}.ip-geo-block-title{width:100px;display:inline-block}.ip-geo-block-result{color:#2786c2;display:inline-block}.ip-geo-block-primary{color:#fff!important;background:#00838f!important;border-color:#00707a!important;text-shadow:none}.ip-geo-block-primary:hover{background-color:#00919e!important;border-color:#00525a!important}ul#ip-geo-block-logs-preset{margin:.25em 0;max-width:600px}ul#ip-geo-block-logs-preset li{float:left;line-height:1.5em;margin-right:1em;min-width:160px}#ip-geo-block-live-loading,.ip-geo-block-loading{height:16px;width:16px;background-size:16px 16px;background-position:center center;background-repeat:no-repeat;margin-left:1em;margin-top:.2em;display:inline-block;vertical-align:top}.ip-geo-block-loading{background-image:url(data:image/gif;base64,R0lGODlhEAAQAPYCAKqqqsbGxlZWVsrKyvr6+ubm5tDQ0K6urmZmZmJiYuzs7IaGhvT09JycnLq6us7Ozurq6o6OjtbW1tra2vDw8CgoKCYmJvz8/NLS0kJCQlJSUqysrPLy8vb29pqamra2tm5ubujo6Kampvj4+IiIiMjIyEhISNzc3OLi4rKysj4+PlBQULi4uJKSkmRkZODg4KKiou7u7iQkJB4eHlpaWhISErCwsHh4eMDAwDIyMi4uLqSkpIKCgr6+vt7e3n5+fggICJCQkAwMDEpKSmBgYHZ2dhgYGBYWFnx8fF5eXk5OTiIiIjAwMIyMjISEhDQ0NJaWltTU1AQEBBwcHGpqaoqKiuTk5CoqKlhYWAoKCtjY2Hp6ehAQEJ6ensLCwkxMTJSUlCwsLAYGBnR0dDg4OFxcXLy8vKCgoA4ODsTExMzMzDw8PERERDY2NqioqHJycrS0tGhoaBQUFEZGRjo6OkBAQICAgHBwcFRUVCAgIGxsbP///wAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgACACwAAAAAEAAQAEAHjIACgoOEhYJsbTGGghcPGIJRbFNNhgQKCheDDkllDQYMHSc4MAcvhTB0aFliggQjmYNEFQ6LAh0+VoIwbFW1GGamhCgfUE5NbgMKtQYLc0a1gjsyR3E2IYwMFASDYDJvtRRWFIJ1TMq1ElqCICpetQoBEoInVCsAhhI2XhyEPUgIIG7waALlwAloCAMBACH5BAkKAAIALAEAAQAOAA4AAAeDgAKCEmBYYRVKJAaCjAcrVzIzRjVoTw2MKRk5Ww4KECkuWTWCE0Rrl4yCTow7bAupsBcCW19psKkjBEQaFLeMHBwINBy+ggoxVQkPxSMFMXBUMMUQPhRWVUU9tyFRLwQCA048cCcjIyFaJQYxjA8NEVBnAClmahCwEANwbjYBJwyMAgEAIfkECQoABQAsAQABAA4ADgAAB4OABYInO29DbC5QUYKMZiBfbCptTBUmIow4LgJBaTExZkVLFTAFKD8JB4yMQUZrBixUXaqqVFwkUG8Ys4wpQiZOWwy7ghBiRk08HcOqblUTy4wlLWbLBCMFCgBdurMjFMoFE24ADxAXFwwKITEEjD5mH2YBDxI+IdeqHCcGAxgv7IwCAQAh+QQJCgAAACwBAAEADgAOAAAHhYAAglYfTVQJSCITgowDVSAISQJKJgkpjA8LWyIGHBQBJCoZBwAQDU44jIxdTxoSAxEfqqpbFWApUCezjA5LWCJdI7uCClNXGyLCwxBHFl4HBcMAKVxfEx8Y0glZCxwlOCjDUkwPACElAygMghftAB6MClpRJygQFB0EuyMKBQUKDPQxCgQAIfkECQoAAAAsAQABAA4ADgAAB4SAAIIKahstTQ0OVoKMJzYeLVU8W29OXowvBztePh0dUTtxVD0AHDgHEoyMKWVvPj4sBqqqLUoiGDgQs4wBJmNqARe7gjEqXxgPwsMxbWw+UQzDAGY6LjEnusNjFmAEBVbRs00zc1EAHRAKHYw2CHIyO4wEHAwjgmJCZDC7F8psC7IEBQIAIfkECQoARwAsAQABAA4ADgAAB4OAR4IMPgMfNg4PCoKMEA84LCkAMB47GIwxBiUTEAQjKD0REQ9HBD4YIYyMATwtBRQnqaqMG0UOEC8ds4wYIEEQBbuMHC4gMYvCRxw0CAwcF8kBGj8EHdDCJCYiRxfXsw0qCROqRDYQECw3ORkpqjpAQjVGMxYrB7MPC0MyFQItEowCAQAh+QQJCgACACwBAAEADgAOAAAHgIACghcUVhIYEigMgowjEC8nUQ8BOGkojAQxITEdAhcxEh9wPoIMFCOMjBMAKTEXHaipjGldDxcEsqkvUAe5sh1NLb6pHTxNbGK9vlE3DU5ZLsNnIA4GbTVVuQcJdpdnS0Z3LAoxXhF4LjiMMBl5FjptKiZ6ZrJRLUkqbCAwJ4yBACH5BAUKAAEALAEAAQAOAA4AAAd/gAGCARcjHDExHASDjAQdHAoFLy8Ugw2MgiMKWhIKAQ9MYpiCEA8YHQtZCaOCJ14vX2g2rAEKZgMyNRC0BCksFUa7rCMANgIzH7QvZw4tMmO0DlAPUV9hHqNeVTC7G2tkTmkUHA8iSFUGgzZlGSYaNC4gTWqYEzA3SQhVH1aDgQA7)}#ip-geo-block-map{height:400px;margin:1em auto}#ip-geo-block-apis div.nav-tab-wrapper{padding-top:0;margin-bottom:1em}#ip-geo-block-geoinfo{white-space:normal;word-wrap:break-word;word-break:break-all}#ip-geo-block-geoinfo ul{margin-top:0;margin-left:1em}.gm-style-iw{width:18em;height:auto!important;height:100%;min-height:100%:}.gm-style-iw ul{margin:.1em}.gm-style-iw li{margin:.2em}svg a{cursor:pointer}svg a:hover>text{fill:#0096dd}svg a>text{fill:#0073aa;text-decoration:underline}table.ip-geo-block-statistics-table{float:right}table.ip-geo-block-statistics-table td,table.ip-geo-block-statistics-table th{width:12em;margin:0;padding:.2em;text-align:right;line-height:1.5em;word-wrap:break-word}table.ip-geo-block-statistics-table tr:nth-child(even){background-color:#eee}table.ip-geo-block-table{margin:1em 0;width:100%;white-space:normal;word-wrap:break-word;word-break:break-all}table.ip-geo-block-table td:first-child{min-width:4.3em;max-width:5em}@media screen and (max-width:782px){#ip-geo-block-whois .panel-body{padding:0 .5em}}#ip-geo-block-scan-code{vertical-align:middle}#ip-geo-block-code-list{display:none;margin-bottom:0}#ip-geo-block-chart-countries{height:200px}#ip-geo-block-chart-daily{height:240px}#ip_geo_block_settings_validation_mimetype+label{padding-top:.25em}#ip_geo_block_settings_validation_mimetype+label+ul{margin-top:.7em}#ip_geo_block_settings_create_user{margin-bottom:.5em}#ip-geo-block-back-to-top a,#ip-geo-block-toggle-sections{box-shadow:none}#ip-geo-block-wp-info textarea{margin-top:.5em;overflow:auto;width:100%;word-wrap:normal;word-break:normal;white-space:pre}#ip-geo-block-back-to-top{margin:0;text-align:right}#ip-geo-block-live-update,#ip-geo-block-open-new{margin-left:1em}.ip-geo-block-menu-link{font-size:13px!important}dfn~.ip-geo-block-icon{margin-left:.4em}.ip-geo-block-icon{position:relative;cursor:pointer;outline:0;box-shadow:none;text-decoration:none;background-color:transparent}.ip-geo-block-icon:active{top:1px}.ip-geo-block-icon span{height:16px;width:16px;margin:0;border:none;display:inline-block;vertical-align:middle;background-size:16px 16px;background-position:center center;background-repeat:no-repeat}.ip-geo-block-icon-cycle span{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAh1BMVEUAda2otLp+rsSHprWHr8IBd7EpfKRGhaNajqeUqrRymKuKoq5yo7prlKgAcqoVe6w8gqQmgq5Tj6wIdqsVdKIshrEMea1Uhp+Anqw0hawDdq4gfKhljqE7hqoLdKYbgbM4jLQygKUGeK8CdawQd6gVeKcad6NKkrSerrZAj7UAc6sAc6rc3NySrVGQAAAALXRSTlP//////////////////////////////////////////////////////////wCl7wv9AAACOklEQVR4Ae2W15rzKgxF9xTZzhTX9B7S/gN6/9ebYqzzGZsw/S7LV3FZgCSIwD/kQ8FVcBU8xatZUczy8luC/ABNOn0DSHEsvyZ4PgLatNCYR3efFxyhTQ8g+qQgJxgv2JefERzJXATRh4LHOUwAHD4S7OGEztRJaN86hAUxtaNWDUf/bRdDBbQMWVDAO8jn89WUhag1MeyCAh6hHofyrliLgZKggDMYgzF3eVAwFq0uCZq5KY0TezjIHDDzC0qqmkwe2ctGDOQVLMkgu+F3/rGXwb4xIPcJ6P3JgkM8wFjmfcFAWfeKQywaAz33BJVuHsUcAt09gVbuLDThAJkdR687ggLmf4gDJLIGV7BydtB8yn3u+fbtuj/LS7G9wZAd1AKK+yxJ1x+aBmibTtgCcEHGHsh0wdbOgNLek4L7lI5BigY8nWuZUQ3qGEXes9JzOKGJztPaGtLslu3lIXJirdxCWkASHGDTMqg7V1DKPplygDG61YJukLHjEErGSXqCSos6xNSOgzP3BDmsQBcchNwkoV8oiNnPA78zIefUgCdJeGIfE7LmFWXsFTCFdzTJ/RlfEMRiSGnFXXbkC7AIeqcKDu4ynseozeouKJiSEYBDwkJyIC1nRUjgblkNWp/e/1vXc2gjoAoLksYgjrrFMi0oDgjEEIDij1scBXMJSH6DAj6RNl7o8MkuLak8Co15/Pk+MRmT0xilQJV/sdWNKg2kTaeroudvNNsDjmejYjSL+e6v2/2r4Cp4BXNajr0H7hRfAAAAAElFTkSuQmCC)}.ip-geo-block-icon-lock span{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3Ny3y9Zzq8dRmb7M1dlXnsIFdK0AcawAcqwphrYAcKvZ29wAb6oJd680jrqlw9MBcqxmo8MUfbJLl75eoMI7kbzX2ttqp8VSmL1YnL8NeK+Tu89DlL1ImMEOebBNmL4OkqMoAAAAAXRSTlMAQObYZgAAAPlJREFUeAG9kAWyhTAQBIPOsCzufv9TPnf4Ll0CSbpmxXwNy3Yc23rz2fV8kPA99433AIQIiGDTCD0lojiOQPXCDSFJIbF16CMWItkQMkF+inZzSLYhFKLl+a9UKTZaqJTZJYtarZuo40chrv9CqJTN+behVi+Cm7RdDgRld6AMgLxrE/dxBz0BEjwBEmD/uIsWPAOAF9A+CE56ufSryr8oqfOYcBbQJ8YkES7COkFOYzTypqCDOTDo2wljaEw4vp1APYyWKd8WMBozylvCpcvmXeHQ5fCegHia4s1FgZcIVeVFeFx1M4MvYG4eBHdYWufC+addBtf8E3vdjBNhWnVQqAAAAABJRU5ErkJggg==)}.ip-geo-block-icon-unlock span{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3NyzydRzq8dRmb7I09hYnsEFdK0AcawAcqzP1toqhrYAcKvZ29wAb6oMeK8zjbqrxtQBcazBz9Zko8MVfbLF0thMmL07kbtpp8WjwtJSmL1YnL+Tu89DlL1JmMEPebBFV++UAAAAAXRSTlMAQObYZgAAAONJREFUeAG9kAWChDAMAIMmJaTFXf7/ynXflvMbnE5j8DU8Pwh8D1yEUYxEGEchWFEJEjEflESBhTQSQm2MRpIotQhZTmgKgMIg5ZlFKBmrGg7UFXJpEQKW8qIKN7YeikJdBJI2BTtXwfyx0L3XoPphvBEliNU49OoxqEa6g4cTST/OYshvi3hV8+FxSNfluG3jqxG8C6h7gF6jU+AODnTsFGSCA5O4I8wpQDq7I5CUAKWQW+AZYOYtoQPoGDeECWDaioBmWQxeBduoWURso+5WpBdw7R4ENTVDcGE435tJwT+xB+vMEnZRNB0YAAAAAElFTkSuQmCC)}.ip-geo-block-icon-find span{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3NzS19rD0NWHtMpGk7kYfbAGda0Req+WtcTT1temwM4AcasAcqwAc6wAcKydvMt1pr8Ab6pqpcLX2doggrKoxdNYm7yzw8u/y9HO1tkKdq4th7Td3t6DrcLL0taxyNPGe/YhAAAAAXRSTlMAQObYZgAAARVJREFUeAGtkkeiwyAMRP2xDfxoRjElvd3/lOkNUlZ5u0GPruan/Bnz96Xadr21rvP/7+ujXsAjom78rj4ApCoERIipqfGB1H7wPmYhw1DXjZI6nOel1oJhVAmdUP0tTEDkVC4AYvqIbaDOCqFV6vwRF0tIeYoo6J/X7ICuPAJl9ZynwiIfB5DXxZlRChulbh8xZci0EHZK3TziJFDL504rEOZ+iR5cVj82DoS7XtSshLJpKqaB0Dg3ZjcsQWKaKiF1gVQlITwh/bw2pgKeEeURhE29yKSzUFF03p1V7Wqj2Y7GfrY9X/NirJsPxKsxfBLSSs5GmH8yjAWPSNd8Yoez4f4/G1nIsksqFtGK1i9e39o0P+EAqaoRLlQ+r94AAAAASUVORK5CYII=)}.ip-geo-block-icon-alert span,span.ip-geo-block-icon-alert{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAkFBMVEXc3Nzc2trWl5DHRDTFOyvOgXfc1tXCLBrEMiHEMyLNcmfaxMLDMSDDLx7bu7jRiYHDLhzDMB/LX1PaxsTDLh3YtrHMY1bWmpPJVknSjYXUkYnZuLTMZVnENCPWlI3QhXzENiXXrqrDLRzXsa3Oal7Pe3Hc2NjVn5nNbmPayMbbwb7ay8rUj4fc09Lbw8Db0dDBbRUDAAAAAXRSTlMAQObYZgAAAPVJREFUeAG9ktXWwyAQBonC12brFvff5f2frr4nBredK2DnTFS8Gst2XM8XZmypIGeWcT4PFABaGIXlClfWG1NiC4Ubu705oKRcY32wTAHl2MdTYEqEK8hIiHgHSnSJeaogMyEWO4BijZCvwII2MS9UJ2BXTh+hQidoEttboBOwq3WBnkCNpQlA2iyAhol2hRu71n97p4fw0Z9/ugoPHCfFA+o/iLfCkyBglRJdICBas7uuey+R56fF14wNanj+/QjwY3aX23cBFn6EiHmHNT/ICYxystv/wJy4UHWGlN2cuPB72tFqAq3dP/Hk3zs0E5LZVryGC/hqGNnUa0SVAAAAAElFTkSuQmCC);vertical-align:bottom}table.form-table th .ip-geo-block-cycle span{vertical-align:text-bottom}.ip-geo-block-list{margin-top:0;margin-bottom:.7em}@media screen and (min-width:782px){ul.ip-geo-block-list .code{width:15em}}.ip-geo-block-list-exceptions label{display:inline-block}.ip-geo-block-list-exceptions dfn{border:none}.ip-geo-block-list-exceptions span.dashicons{font-size:14px}.ip-geo-block-list-exceptions a.ip-geo-block-icon{margin-left:.3em;outline:0;box-shadow:none;text-decoration:none;background-color:transparent}.form-table td p.ip-geo-block-desc,.form-table td p.ip-geo-block-find-desc{color:#666;font-size:13px!important;margin:4px 0 .5em .5em}.ip-geo-block-find-desc{display:none}.ip-geo-block-admin-post{color:#c43322;margin-left:.25em}.ip-geo-block-warn{color:#c43322;font-weight:700}input#ip_geo_block_settings_behavior_time,input#ip_geo_block_settings_behavior_view{width:3.5em}.ip-geo-block-top-list{display:inline-table;list-style-position:outside;margin:0 2em .5em 1.75em}.ip-geo-block-top-list h4{margin:1em 0}.ip-geo-block-top-list li code{background:0 0}.ip-geo-block-network{margin-bottom:1em}.ip-geo-block-container{margin:0 auto;padding:0 1em;position:relative;width:100%}.ip-geo-block-row{display:flex;flex-direction:column;align-items:flex-start;align-items:stretch;padding:0;width:100%}.ip-geo-block-row .ip-geo-block-column{display:block;flex:1 1 auto;align-self:flex-start;margin-left:0;max-width:100%;width:100%}.ip-geo-block-row .ip-geo-block-column.column-20{flex:0 0 20%;max-width:20%}.ip-geo-block-row .ip-geo-block-column.column-25{flex:0 0 25%;max-width:25%}.ip-geo-block-row .ip-geo-block-column.column-33{flex:0 0 33.3333%;max-width:33.3333%}.ip-geo-block-row .ip-geo-block-column.column-50{flex:0 0 50%;max-width:50%}@media (min-width:40rem){.ip-geo-block-row{flex-direction:row;margin-left:-2em;width:calc(100% + 2em)}.ip-geo-block-row .ip-geo-block-column{margin-bottom:inherit;padding:0 1em}}table.ip-geo-block-dataTable{clear:none!important}table.ip-geo-block-dataTable td,table.ip-geo-block-dataTable th{text-align:right}table.ip-geo-block-dataTable td:nth-child(n+2),table.ip-geo-block-dataTable th:nth-child(n+2){padding-left:0!important}table.ip-geo-block-dataTable th{white-space:nowrap}table.ip-geo-block-dataTable>thead>tr{line-height:1.8em}table.ip-geo-block-dataTable>tbody>tr{cursor:pointer}table.ip-geo-block-dataTable.no-footer,table.ip-geo-block-dataTable>thead>tr>td,table.ip-geo-block-dataTable>thead>tr>th{border-bottom:1px solid #ddd}table.ip-geo-block-dataTable thead td,table.ip-geo-block-dataTable thead th{padding:10px 16px}#ip-geo-block-statistics-cache td:nth-child(3),#ip-geo-block-validation-logs td:nth-child(4){min-width:1.6em}div[class*=ip-geo-block] .dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #ddd}table.ip-geo-block-dataTable.nowrap td,table.ip-geo-block-dataTable>tbody>tr>td span{white-space:normal!important;word-wrap:break-word!important;word-break:break-all!important}table.ip-geo-block-dataTable>tbody>tr>td span{display:inline-block}.ip-geo-block-settings-folding input[type=checkbox]{margin-right:.5em}table.ip-geo-block-dataTable input[type=checkbox]{margin:0;max-height:16px;max-width:16px;vertical-align:middle}table.ip-geo-block-dataTable>tbody>tr>td:first-child,table.ip-geo-block-dataTable>thead>tr>th:first-child{padding:8px 4px 8px 1.4em;text-align:left}table.collapsed>tbody>tr>td.dataTables_empty:first-child::before,table.ip-geo-block-dataTable>tbody>tr>td.dataTables_empty{border:none;text-align:center}table.ip-geo-block-dataTable thead>tr>th:first-child.sorting_asc{background-image:none!important}table.ip-geo-block-dataTable.display tbody tr.even>.sorting_1,table.ip-geo-block-dataTable.display tbody tr.odd>.sorting_1,table.ip-geo-block-dataTable.display tbody tr:hover>.sorting_1{background-color:inherit!important}table.ip-geo-block-dataTable.collapsed>tbody>tr>td:first-child{padding:8px 4px 8px 8px!important}table.collapsed>tbody>tr.parent>td:first-child::before,table.collapsed>tbody>tr>td:first-child::before{content:'';height:0;width:0;display:inline-block;border-radius:0;border:5px solid transparent;box-shadow:none;position:relative;background-color:transparent}table.collapsed>tbody>tr>td:first-child::before{border-left:5px solid #555;top:1px;left:-2px}table.collapsed>tbody>tr.parent>td:first-child::before{border-top:5px solid #555;top:4px;left:-4px}table.collapsed>tbody>tr.child>td:first-child::before{border:none}table.collapsed>tbody>tr.child>td.child>ul li{border:none;padding:0;margin:0;line-height:1.8em}table.collapsed>tbody>tr.child>td.child>ul li span.dtr-data,table.collapsed>tbody>tr.child>td.child>ul li span.dtr-title{font-size:13px!important;display:block;white-space:normal;word-wrap:break-word;word-break:break-all}table.collapsed>tbody>tr.child>td.child>ul li span.dtr-data{margin-left:1.25em;margin-right:.3em}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_length{padding-top:.15em;margin:.5em 0 0 .3em;position:relative;display:inline-block}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_length:after{content:'';width:6px;height:6px;border:0;border-bottom:solid 2px #999;border-right:solid 2px #999;-ms-transform:rotate(45deg);-webkit-transform:rotate(45deg);transform:rotate(45deg);position:absolute;top:50%;right:10px;margin-top:-4px}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_length select{padding-top:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;font-size:13px!important;line-height:1.4em;width:100%;height:2.05em!important;background:0 0;position:relative;z-index:1;padding:.125em 1.5em .125em .25em;border:1px solid #ddd;border-radius:4px;box-shadow:none}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_length select::-ms-expand{display:none}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate{float:none;text-align:center;margin-bottom:1em;margin-top:0!important}@media screen and (min-width:640px){div[class*=ip-geo-block] .dataTables_wrapper .dataTables_length{margin:.5em 0 0 .6em}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate{position:relative;left:-2.25em}}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.current,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:active,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:hover,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:active,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:hover,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button:active,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button:hover,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate span.ellipsis{min-width:2em;background:inherit;border-color:#ddd;border-radius:0;border-image:none;border-style:solid;border-width:1px 1px 1px 0;box-shadow:none;margin:.5em 0 0 0;padding:.25em 0;display:inline-block;text-decoration:none}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate:active>a.paginate_button:first-child,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate:hover>a.paginate_button:first-child,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate>a.paginate_button:first-child{border-left-width:1px;border-bottom-left-radius:4px;border-top-left-radius:4px}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate:active>a.paginate_button:last-child,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate:hover>a.paginate_button:last-child,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate>a.paginate_button:last-child{border-bottom-right-radius:4px;border-top-right-radius:4px}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button{color:#0073aa!important}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button:hover{color:#0096dd!important;background-color:#fff}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:active,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:hover,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate span.ellipsis{cursor:default;color:#999!important;background-color:transparent}div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.current,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:active,div[class*=ip-geo-block] .dataTables_wrapper .dataTables_paginate a.paginate_button.current:hover{cursor:default;color:#444!important;background-color:#fff!important}#ip-geo-block-1 #ip-geo-block-section-2 .panel-body,#ip-geo-block-4 #ip-geo-block-section-0 .panel-body{padding:0}#ip-geo-block-1 #ip-geo-block-section-2 table.form-table,#ip-geo-block-4 #ip-geo-block-section-0 table.form-table{margin-left:1em;max-width:95%}#ip-geo-block-select-duration,#ip-geo-block-select-layout,#ip-geo-block-select-target{margin:0}#ip-geo-block-select-duration li,#ip-geo-block-select-layout li,#ip-geo-block-select-target li{float:left;margin-right:1.5em}#ip-geo-block-select-duration li label,#ip-geo-block-select-target li label{cursor:pointer}#ip_geo_block_settings_search_filter{width:16em;padding-top:3px}table.ip-geo-block-dataTable.display tbody tr.ip-geo-block-passed{background-color:#edf6ff!important}table.ip-geo-block-dataTable.display tbody tr.ip-geo-block-blocked{background-color:#ffefef!important}.ip-geo-block-new-passed{animation:ip-geo-block-flash-passed 1s ease-out 0s 1 normal both running}.ip-geo-block-new-blocked{animation:ip-geo-block-flash-blocked 1s ease-out 0s 1 normal both running}@keyframes ip-geo-block-flash-passed{0%{background-color:gold}100%{background-color:#edf6ff}}@keyframes ip-geo-block-flash-blocked{0%{background-color:gold}100%{background-color:#ffefef}}mark{padding:0;background:gold}// Gold #ip-geo-block-live-log{margin:0}#ip-geo-block-live-log li{float:left;margin-right:3em}#ip-geo-block-live-log li:last-child{margin-right:0}#ip-geo-block-live-log li input[type=radio]{visibility:hidden;position:absolute}#ip-geo-block-live-log li input[type=radio]+label{display:inline-block;margin:-2px;padding:4px 12px;margin-bottom:0;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);border-bottom-color:#b3b3b3;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05)}#ip-geo-block-live-log li input[type=radio]:checked+label{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);background-color:#e0e0e0}.ip-geo-block-live-timer{height:1em;width:1em;margin:0;position:relative;top:0;left:0}.ip-geo-block-live-timer:before{content:"";display:block;height:1em;width:1em;background:#0073aa;border-radius:50%;position:absolute;top:0;left:0}.ip-geo-block-live-timer:after{display:none}.ip-geo-block-live-timer>div{position:absolute;width:1em;height:1em;clip:rect(0,1em,1em,.5em)}.ip-geo-block-live-timer>div:before{content:" ";position:absolute;width:1em;height:1em;border-radius:.5em;clip:rect(0,.5em,1em,0);background-color:#f1f1f1;transform:rotate(0)}.ip-geo-block-live-timer>div:first-child:before{animation:30s spin-timer linear forwards}.ip-geo-block-live-timer>div:last-child{transform:rotate(180deg)}.ip-geo-block-live-timer>div:last-child:before{transform:rotate(0);animation:30s spin-timer linear 30s forwards}@keyframes spin-timer{0%{transform:rotate(0)}100%{transform:rotate(180deg)}}.ip-geo-block-subitem{margin-left:1.7em}.ip-geo-block-subitem:before{content:"\00bb";position:absolute;left:2em}.ip-geo-block-subitem dfn{vertical-align:middle}.ip-geo-block-subitem-parent td,.ip-geo-block-subitem-parent th{padding-top:0}:placeholder-shown{color:#888}::-webkit-input-placeholder{color:#888}:-moz-placeholder{color:#888;opacity:1}::-moz-placeholder{color:#888;opacity:1}:-ms-input-placeholder{color:#888}
\ No newline at end of file
diff --git a/wp/wp-content/plugins/ip-geo-block/admin/css/cidr.min.css b/wp/wp-content/plugins/ip-geo-block/admin/css/cidr.min.css
deleted file mode 100644
index 09539b5c..00000000
--- a/wp/wp-content/plugins/ip-geo-block/admin/css/cidr.min.css
+++ /dev/null
@@ -1 +0,0 @@
-*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{margin:8xp;font-size:14px;line-height:1.4}.container{margin:0;padding:0}.clr:after,.col:after,.container:after,.row:after{content:"";display:table;clear:both}.row{padding-bottom:0}.col{display:block;float:left;width:100%}.span_2{width:8.33333333333%}.span_11{width:45.8333333333%}.span_24{width:100%}fieldset{border:none;margin:0;padding:.5rem}textarea{width:100%;height:4.5rem;resize:horizontal;border:1px solid #ccc;font-size:12px;font-family:Consolas,Monaco,monospace}legend input[type=button]{margin-left:.5rem;vertical-align:middle}#j,#i{display:-ms-flexbox;display:-webkit-box;display:-webkit-flex;display:flex;justify-content:center;align-items:center}#j{padding:0 .5rem}ul#h{padding:1.5rem 0 0;list-style:none}ul#h li{width:100%;margin:.1rem 0;display:inline-block}ul#h li input{padding:0}#g{height:3em;text-align:center;border:1px solid #ccc;padding:.5rem;font-size:12px;font-family:Consolas,Monaco,monospace}
\ No newline at end of file
diff --git a/wp/wp-content/plugins/ip-geo-block/admin/css/fonts/icomoon.eot b/wp/wp-content/plugins/ip-geo-block/admin/css/fonts/icomoon.eot
deleted file mode 100644
index ae697d386406c8c68cb2091c84ee3b4caeda3562..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 3988
zcmbtXU2Gd!6+YMF8OL_x*dE)HIF9j*xaze#&YwbBLB!?I9Wk?cv?CfTp)J=5v**V4brh|Va@cqU_e#vhsTOl#(v z%yaSt`6&59`7uR|qD(PE@tKmVEKokF{7`v4D>KWUwJz(IUMaoC^m?<`+3cijI(vEc zshs#6P0o^>##~YEsNBW5jlDbf*7RQ5`($31JYC+3yfgXT^GD~um4Bf?TwpC&UvO2G zrFvYoRn1oSQBPCvD~u`}TsXh*`=a=w+M?A(7yD%Nd9=^gVs3H2;unjLm2@c4maHnd z*jL{7@xD9z3Hw#_o8Rwb{~rCV{Wq7gO8b_+RC;_s*8!#h8wa9+B?Dg?_+432+1RoV z2Jr@!4O%ehhjK~zW97RlqANyLyjgLjvY>Ki<+p>o4R#FPJ|uj|h#{+nTpg+&I%{a- zu(V;15Bp+x+u{1*o2vL#L#kF(U4E$Wp_d;zJtAYo)DcG?PI|cE;oXn4eZ=s{M&sbAKm^~=f@^JcH;5;$Co@oJyHF{_9weMIpxXI6Z=ejW0GLfm`Qsl zizm;T{QFZwpV~a7!<30rPCeb{>D5!irdp>Sd#2Yji=O2?tABRibF$~=J$GxGZrbP5 z#nb0ZZzc}?@{<{w#5uwd=N_6wg|c=c7?tA}38 zdu`344vVHQy0KWl_^Ty-mTXv>xOC1k-m-Daepo(a`L5R$udiCscE$7+f2=gEY<#2q zjh(CHt5&_){>_=IS*snZ&%HI`tpk5o|9#V%lr>A%#;u+HHhSCf_K)w3dgti6e(Scs zt9W OyMABhz76~3`!^j>9@u;^`{2iidLP>MrTWWH50@PN z;>ds_2agUu`qi-!#~Q!VeRcM0!`HulGwz$4-%dQvJwENbi0|fn-~Rih|LFdYwT+pL zADvL2*mJVt Bn>iliSr8bvV{+|B(_RD3LzrSLz3LF J6o2mN4AYC^l4%!{zaVf(0Q|OCqdn zvE9T7L~$rKi^Jmbc|lyZPzJ yH2TPGh> z@w?8dxOn1Mtt}&N>AI&9)h|`*3b!w_XSO;t_$2+?yHj?2={R+%C~5Zcr{8;d=iz_; z{`&e)j-0+cq-NaIIV(1Ndh~}Y@;*ar>z{dL<;Gpd&RmT|EEbfOL(0VGaWhB}I!mHB zP=c}X(Ol`I7h`Y %Z;t1XrYhP2s ztdj1|1D6NKJ>K#7qGh{!p0>}bxLn@vbmgoH=hwssJA=<4SkZwt!L1RF@{taiQ8g^^ zh+yJd2e2K2jX)OQi2f4}5mKQFnA&2eCOO0dh^W-kQq%*0AjGGl$hs0VG~nC9ycn}0 zR86(>z@w>dE*@}tN&@fN2(^b`rKAMLJ?Z&p^kjtz%Pxm-012ADK?qh0UH5x@kqqI_ zjAe->SrWNO?D|d^s6gz+RCC!Dvpo8v7qgpT%m^2cf+;WDDOd&Yst47vxgJ!acRg5? zTL+cOYSvAZK?FUU*n!-!<-!+ZQqU-)8Nb`R^1>)sdw~Gzyf04*13GUCz=Vj`Eis $2{(pe4OO#ZG{aQtsSpL<1{L@+f}|gm=A3Ya%k{~hDTdeU=X?Y z6Ub=R$7=FPm+O4#l~$9@z1SV1(dkNEpK)~K1bEHAoYpzCw7VRUcrDCYiAxTvQg*A^ z;8Uo`=8CzuP zHNYC5&Rtuf$y}
-8)ts3J{n(R_|@1^|*%0cEDOK|y6iV-$h;NINZIj)^R z>;Qb&&%qy1^i+UIF2#Z<$Y@K4-2%iRxMc))&8RWyOUjGNA$1<(^G#|zUhIL;oP+mX zBg!wTaJL*$QDiMK-Er^FEkzs?xX8X={*S8?uox(D_dnkqL$?%eP*h~|*&2krt?r#j zOa^+9)txu4vRiw9mB+h)3)ib0{2Ra^EQK#(gXIKlZ>+Jx&IuVGyz1;4OHue)7zPeI zZxUW6!lP+4o}|Hj072p1eGKC oPb@xO}Z42v7m+^=r`>R0}K6X5@f9e;wf&uh#(`TaAm;T0=FiF9#P3r}d^9{1!{B ziqm6EW8B?_$-`!;@unNJ2E2RhW3QS9s|9e_MlCPA3y$9s@HTIl%QAflQ#`Q@ykSBr z9_Q?38L%w5?%Og#wYlCTqD^?*$JNF9T-L$w9zvuBo796%MC9KP8hA-E0Myb#d@T1M zEtDs9I)B@ La_OKQW1AEK>QKpX=O%)i%s-SL|MQ79DhlmUUi#Rl<;h_aP zx97r~Mu$O!s4X5GGY slJsCegLSRi7KabUa(u>JX#DAg}Z*|Y? zVD0*Teixkg^MhgVe?=Q=Afvt0S;ad+pdAQRVW3G2?Y#qlIe3s0H#sl0!vLD|DR zqISayHM#Ko5I<~N*zDR2-`^cLUb^P Wc!->AWwHKYd0TAcPzP Y=)!HkCK$=U231X{2~oTgP@Nq&5v<}={o$mV#5d6m7{_io(VQCqambK- Y16@Zf7?Q8!JB-NJ(KYBs*Ff|C0Zg4MIsgCw diff --git a/wp/wp-content/plugins/ip-geo-block/admin/datatables/images/favicon.ico b/wp/wp-content/plugins/ip-geo-block/admin/datatables/images/favicon.ico deleted file mode 100644 index 6eeaa2a0d393190ce748107222d9a026f992e4a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 894 zcmZQzU<5(|0R|u`!H~hsz#zuJz@P!dKp_SNAO?xUfG{@$0|>*we Y}F;x;`B~@Mg`jC-vo5%k$%{OoKy1zkdA+(K2o3 zEDKGQQ~gcX+N!Tt Ej1|9e2tL(rheJva*5dKY#gZsIRxM zB;!h7 5Wi?9l5?>z>S-`t`=OAFp5C?(007k>qM(bnVuyja#;c*qL9N z(Q%=@`f7d2?T&^wySIHjy#MKh?rZrO7i!Bt-@f(!@WDrwB`uD&)%Eqcd3o(gVV7ri zp6ji@(BF7(+uE0x&)(R!?s#YIg_7JW1=-KHZv1@s(DS xD9<^am-%+f#!uU}z9=j>5*%b{WE2`20#tutPWS1# zz4s39d~xOMwaqJzOl{rMU%#oo=xj&xyY1WF&71o?Hs-LOkA D^4SRbV?yXz(e#efNwKXpT1J^s+yE;1`KXoe5&f?1A$ tYso}un=1c3AzCL>B&D=RpqN3i1hL&lnclP!D`u*G0#bsJv!oAH) z-rc|T`^Wdkrw?7(xb)_p%`Y#WdAn`Pvz+W#0Rbo6-Ha3zp1gPgjDkZ)k6Gz!@9D0( zG^hL4?)Be4zWep#`{$>RUhUoaq@wgyfd9*oU{6tz+SXQhl3284sj;T&{L=I*bGxt4 z@4vfX%A<*$FN^a&MMa! gnPb zQo)$K!&zxT#Nl4)@@eaKRKFIxD0MA=SMcSM^3P$9Oy*ctFW>q)FZA%;zI(f$pBG-3 zcra-}mPXX3M|zCB?fv&MbDT3) >ro_ diff --git a/wp/wp-content/plugins/ip-geo-block/admin/datatables/images/sort_both.png b/wp/wp-content/plugins/ip-geo-block/admin/datatables/images/sort_both.png deleted file mode 100644 index c4fbedfe341e57233f21936454bb4465217f6167..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRx!3HE}ruUu)Qs$m6jv*C{$vcXl^SRDQWBb$o zkkRmgz16bSjQ Ds1IQRZncrTx`1JHH`Pgg&ebxsLQ05eBP761SM diff --git a/wp/wp-content/plugins/ip-geo-block/admin/datatables/images/sort_desc_disabled.png b/wp/wp-content/plugins/ip-geo-block/admin/datatables/images/sort_desc_disabled.png deleted file mode 100644 index 498436626ea8e73fa160d8ffd341307486b78840..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRx!3HE}ruUu)Qo5cljv*C{$vcXl^SRD=#nvNb zkaeKmX~r}*0kf7D1_zeTT*qdxAbZ(r#xMRJ3?ZK_j;`e2{tKv)!PC{xWt~$(697L- BAHx6u diff --git a/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/LICENSE b/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/LICENSE deleted file mode 100644 index 605df390..00000000 --- a/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016–2017 Julian Motz - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/dataTables.responsive.js b/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/dataTables.responsive.js deleted file mode 100644 index 4abce0bd..00000000 --- a/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/dataTables.responsive.js +++ /dev/null @@ -1,1255 +0,0 @@ -/*! Responsive 2.1.1 - * 2014-2016 SpryMedia Ltd - datatables.net/license - */ - -/** - * @summary Responsive - * @description Responsive tables plug-in for DataTables - * @version 2.1.1 - * @file dataTables.responsive.js - * @author SpryMedia Ltd (www.sprymedia.co.uk) - * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2014-2016 SpryMedia Ltd. - * - * This source file is free software, available under the following license: - * MIT license - https://datatables.net/license/mit - * - * This source file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. - * - * For details please refer to: https://www.datatables.net - */ -(function( factory ){ - if ( typeof define === 'function' && define.amd ) { - // AMD - define( ['jquery', 'datatables.net'], function ( $ ) { - return factory( $, window, document ); - } ); - } - else if ( typeof exports === 'object' ) { - // CommonJS - module.exports = function (root, $) { - if ( ! root ) { - root = window; - } - - if ( ! $ || ! $.fn.dataTable ) { - $ = require('datatables.net')(root, $).$; - } - - return factory( $, root, root.document ); - }; - } - else { - // Browser - factory( jQuery, window, document ); - } -}(function( $, window, document, undefined ) { -'use strict'; -var DataTable = $.fn.dataTable; - - -/** - * Responsive is a plug-in for the DataTables library that makes use of - * DataTables' ability to change the visibility of columns, changing the - * visibility of columns so the displayed columns fit into the table container. - * The end result is that complex tables will be dynamically adjusted to fit - * into the viewport, be it on a desktop, tablet or mobile browser. - * - * Responsive for DataTables has two modes of operation, which can used - * individually or combined: - * - * * Class name based control - columns assigned class names that match the - * breakpoint logic can be shown / hidden as required for each breakpoint. - * * Automatic control - columns are automatically hidden when there is no - * room left to display them. Columns removed from the right. - * - * In additional to column visibility control, Responsive also has built into - * options to use DataTables' child row display to show / hide the information - * from the table that has been hidden. There are also two modes of operation - * for this child row display: - * - * * Inline - when the control element that the user can use to show / hide - * child rows is displayed inside the first column of the table. - * * Column - where a whole column is dedicated to be the show / hide control. - * - * Initialisation of Responsive is performed by: - * - * * Adding the class `responsive` or `dt-responsive` to the table. In this case - * Responsive will automatically be initialised with the default configuration - * options when the DataTable is created. - * * Using the `responsive` option in the DataTables configuration options. This - * can also be used to specify the configuration options, or simply set to - * `true` to use the defaults. - * - * @class - * @param {object} settings DataTables settings object for the host table - * @param {object} [opts] Configuration options - * @requires jQuery 1.7+ - * @requires DataTables 1.10.3+ - * - * @example - * $('#example').DataTable( { - * responsive: true - * } ); - * } ); - */ -var Responsive = function ( settings, opts ) { - // Sanity check that we are using DataTables 1.10 or newer - if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.3' ) ) { - throw 'DataTables Responsive requires DataTables 1.10.3 or newer'; - } - - this.s = { - dt: new DataTable.Api( settings ), - columns: [], - current: [] - }; - - // Check if responsive has already been initialised on this table - if ( this.s.dt.settings()[0].responsive ) { - return; - } - - // details is an object, but for simplicity the user can give it as a string - // or a boolean - if ( opts && typeof opts.details === 'string' ) { - opts.details = { type: opts.details }; - } - else if ( opts && opts.details === false ) { - opts.details = { type: false }; - } - else if ( opts && opts.details === true ) { - opts.details = { type: 'inline' }; - } - - this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts ); - settings.responsive = this; - this._constructor(); -}; - -$.extend( Responsive.prototype, { - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Constructor - */ - - /** - * Initialise the Responsive instance - * - * @private - */ - _constructor: function () - { - var that = this; - var dt = this.s.dt; - var dtPrivateSettings = dt.settings()[0]; - var oldWindowWidth = $(window).width(); - - dt.settings()[0]._responsive = this; - - // Use DataTables' throttle function to avoid processor thrashing on - // resize - $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () { - // iOS has a bug whereby resize can fire when only scrolling - // See: https://stackoverflow.com/questions/8898412 - var width = $(window).width(); - - if ( width !== oldWindowWidth ) { - that._resize(); - oldWindowWidth = width; - } - } ) ); - - // DataTables doesn't currently trigger an event when a row is added, so - // we need to hook into its private API to enforce the hidden rows when - // new data is added - dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) { - if ( $.inArray( false, that.s.current ) !== -1 ) { - $('>td, >th', tr).each( function ( i ) { - var idx = dt.column.index( 'toData', i ); - - if ( that.s.current[idx] === false ) { - $(this).css('display', 'none'); - } - } ); - } - } ); - - // Destroy event handler - dt.on( 'destroy.dtr', function () { - dt.off( '.dtr' ); - $( dt.table().body() ).off( '.dtr' ); - $(window).off( 'resize.dtr orientationchange.dtr' ); - - // Restore the columns that we've hidden - $.each( that.s.current, function ( i, val ) { - if ( val === false ) { - that._setColumnVis( i, true ); - } - } ); - } ); - - // Reorder the breakpoints array here in case they have been added out - // of order - this.c.breakpoints.sort( function (a, b) { - return a.width < b.width ? 1 : - a.width > b.width ? -1 : 0; - } ); - - this._classLogic(); - this._resizeAuto(); - - // Details handler - var details = this.c.details; - - if ( details.type !== false ) { - that._detailsInit(); - - // DataTables will trigger this event on every column it shows and - // hides individually - dt.on( 'column-visibility.dtr', function (e, ctx, col, vis) { - that._classLogic(); - that._resizeAuto(); - that._resize(); - } ); - - // Redraw the details box on each draw which will happen if the data - // has changed. This is used until DataTables implements a native - // `updated` event for rows - dt.on( 'draw.dtr', function () { - that._redrawChildren(); - } ); - - $(dt.table().node()).addClass( 'dtr-'+details.type ); - } - - dt.on( 'column-reorder.dtr', function (e, settings, details) { - that._classLogic(); - that._resizeAuto(); - that._resize(); - } ); - - // Change in column sizes means we need to calc - dt.on( 'column-sizing.dtr', function () { - that._resizeAuto(); - that._resize(); - }); - - // On Ajax reload we want to reopen any child rows which are displayed - // by responsive - dt.on( 'preXhr.dtr', function () { - var rowIds = []; - dt.rows().every( function () { - if ( this.child.isShown() ) { - rowIds.push( this.id(true) ); - } - } ); - - dt.one( 'draw.dtr', function () { - dt.rows( rowIds ).every( function () { - that._detailsDisplay( this, false ); - } ); - } ); - }); - - dt.on( 'init.dtr', function (e, settings, details) { - that._resizeAuto(); - that._resize(); - - // If columns were hidden, then DataTables needs to adjust the - // column sizing - if ( $.inArray( false, that.s.current ) ) { - dt.columns.adjust(); - } - } ); - - // First pass - draw the table for the current viewport size - this._resize(); - }, - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Private methods - */ - - /** - * Calculate the visibility for the columns in a table for a given - * breakpoint. The result is pre-determined based on the class logic if - * class names are used to control all columns, but the width of the table - * is also used if there are columns which are to be automatically shown - * and hidden. - * - * @param {string} breakpoint Breakpoint name to use for the calculation - * @return {array} Array of boolean values initiating the visibility of each - * column. - * @private - */ - _columnsVisiblity: function ( breakpoint ) - { - var dt = this.s.dt; - var columns = this.s.columns; - var i, ien; - - // Create an array that defines the column ordering based first on the - // column's priority, and secondly the column index. This allows the - // columns to be removed from the right if the priority matches - var order = columns - .map( function ( col, idx ) { - return { - columnIdx: idx, - priority: col.priority - }; - } ) - .sort( function ( a, b ) { - if ( a.priority !== b.priority ) { - return a.priority - b.priority; - } - return a.columnIdx - b.columnIdx; - } ); - - // Class logic - determine which columns are in this breakpoint based - // on the classes. If no class control (i.e. `auto`) then `-` is used - // to indicate this to the rest of the function - var display = $.map( columns, function ( col ) { - return col.auto && col.minWidth === null ? - false : - col.auto === true ? - '-' : - $.inArray( breakpoint, col.includeIn ) !== -1; - } ); - - // Auto column control - first pass: how much width is taken by the - // ones that must be included from the non-auto columns - var requiredWidth = 0; - for ( i=0, ien=display.length ; i = size ) { - add( colIdx, breakpoints[i].name ); - } - } - } - else if ( operator === 'not-' ) { - // Add all but this breakpoint - for ( i=0, ien=breakpoints.length ; i =0 ; i-- ) { - if ( width <= breakpoints[i].width ) { - breakpoint = breakpoints[i].name; - break; - } - } - - // Show the columns for that break point - var columnsVis = this._columnsVisiblity( breakpoint ); - this.s.current = columnsVis; - - // Set the class before the column visibility is changed so event - // listeners know what the state is. Need to determine if there are - // any columns that are not visible but can be shown - var collapsedClass = false; - for ( i=0, ien=columns.length ; i ') - .append( footerCells ) - .appendTo( clonedFooter ); - } - - $(' ') - .append( headerCells ) - .appendTo( clonedHeader ); - - // In the inline case extra padding is applied to the first column to - // give space for the show / hide icon. We need to use this in the - // calculation - if ( this.c.details.type === 'inline' ) { - $(clonedTable).addClass( 'dtr-inline collapsed' ); - } - - // It is unsafe to insert elements with the same name into the DOM - // multiple times. For example, cloning and inserting a checked radio - // clears the chcecked state of the original radio. - $( clonedTable ).find( '[name]' ).removeAttr( 'name' ); - - var inserted = $('') - .css( { - width: 1, - height: 1, - overflow: 'hidden' - } ) - .append( clonedTable ); - - inserted.insertBefore( dt.table().node() ); - - // The cloned header now contains the smallest that each column can be - headerCells.each( function (i) { - var idx = dt.column.index( 'fromVisible', i ); - columns[ idx ].minWidth = this.offsetWidth || 0; - } ); - - inserted.remove(); - }, - - /** - * Set a column's visibility. - * - * We don't use DataTables' column visibility controls in order to ensure - * that column visibility can Responsive can no-exist. Since only IE8+ is - * supported (and all evergreen browsers of course) the control of the - * display attribute works well. - * - * @param {integer} col Column index - * @param {boolean} showHide Show or hide (true or false) - * @private - */ - _setColumnVis: function ( col, showHide ) - { - var dt = this.s.dt; - var display = showHide ? '' : 'none'; // empty string will remove the attr - - $( dt.column( col ).header() ).css( 'display', display ); - $( dt.column( col ).footer() ).css( 'display', display ); - dt.column( col ).nodes().to$().css( 'display', display ); - }, - - - /** - * Update the cell tab indexes for keyboard accessibility. This is called on - * every table draw - that is potentially inefficient, but also the least - * complex option given that column visibility can change on the fly. Its a - * shame user-focus was removed from CSS 3 UI, as it would have solved this - * issue with a single CSS statement. - * - * @private - */ - _tabIndexes: function () - { - var dt = this.s.dt; - var cells = dt.cells( { page: 'current' } ).nodes().to$(); - var ctx = dt.settings()[0]; - var target = this.c.details.target; - - cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' ); - - var selector = typeof target === 'number' ? - ':eq('+target+')' : - target; - - // This is a bit of a hack - we need to limit the selected nodes to just - // those of this table - if ( selector === 'td:first-child, th:first-child' ) { - selector = '>td:first-child, >th:first-child'; - } - - $( selector, dt.rows( { page: 'current' } ).nodes() ) - .attr( 'tabIndex', ctx.iTabIndex ) - .data( 'dtr-keyboard', 1 ); - } -} ); - - -/** - * List of default breakpoints. Each item in the array is an object with two - * properties: - * - * * `name` - the breakpoint name. - * * `width` - the breakpoint width - * - * @name Responsive.breakpoints - * @static - */ -Responsive.breakpoints = [ - { name: 'desktop', width: Infinity }, - { name: 'tablet-l', width: 1024 }, - { name: 'tablet-p', width: 768 }, - { name: 'mobile-l', width: 480 }, - { name: 'mobile-p', width: 320 } -]; - - -/** - * Display methods - functions which define how the hidden data should be shown - * in the table. - * - * @namespace - * @name Responsive.defaults - * @static - */ -Responsive.display = { - childRow: function ( row, update, render ) { - if ( update ) { - if ( $(row.node()).hasClass('parent') ) { - row.child( render(), 'child' ).show(); - - return true; - } - } - else { - if ( ! row.child.isShown() ) { - row.child( render(), 'child' ).show(); - $( row.node() ).addClass( 'parent' ); - - return true; - } - else { - row.child( false ); - $( row.node() ).removeClass( 'parent' ); - - return false; - } - } - }, - - childRowImmediate: function ( row, update, render ) { - if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) { - // User interaction and the row is show, or nothing to show - row.child( false ); - $( row.node() ).removeClass( 'parent' ); - - return false; - } - else { - // Display - row.child( render(), 'child' ).show(); - $( row.node() ).addClass( 'parent' ); - - return true; - } - }, - - // This is a wrapper so the modal options for Bootstrap and jQuery UI can - // have options passed into them. This specific one doesn't need to be a - // function but it is for consistency in the `modal` name - modal: function ( options ) { - return function ( row, update, render ) { - if ( ! update ) { - // Show a modal - var close = function () { - modal.remove(); // will tidy events for us - $(document).off( 'keypress.dtr' ); - }; - - var modal = $('') - .append( $('') - .append( $('') - .append( render() ) - ) - .append( $(' ×' ) - .click( function () { - close(); - } ) - ) - ) - .append( $('') - .click( function () { - close(); - } ) - ) - .appendTo( 'body' ); - - $(document).on( 'keyup.dtr', function (e) { - if ( e.keyCode === 27 ) { - e.stopPropagation(); - - close(); - } - } ); - } - else { - $('div.dtr-modal-content') - .empty() - .append( render() ); - } - - if ( options && options.header ) { - $('div.dtr-modal-content').prepend( - ''+options.header( row )+'
' - ); - } - }; - } -}; - - -/** - * Display methods - functions which define how the hidden data should be shown - * in the table. - * - * @namespace - * @name Responsive.defaults - * @static - */ -Responsive.renderer = { - listHidden: function () { - return function ( api, rowIdx, columns ) { - var data = $.map( columns, function ( col ) { - return col.hidden ? - '- '+ - ''+ - col.title+ - ' '+ - ''+ - col.data+ - ''+ - '
' : - ''; - } ).join(''); - - return data ? - $('').append( data ) : - false; - } - }, - - tableAll: function ( options ) { - options = $.extend( { - tableClass: '' - }, options ); - - return function ( api, rowIdx, columns ) { - var data = $.map( columns, function ( col ) { - return '
'+ - ' '; - } ).join(''); - - return $(''+col.title+':'+' '+ - ''+col.data+' '+ - '').append( data ); - } - } -}; - -/** - * Responsive default settings for initialisation - * - * @namespace - * @name Responsive.defaults - * @static - */ -Responsive.defaults = { - /** - * List of breakpoints for the instance. Note that this means that each - * instance can have its own breakpoints. Additionally, the breakpoints - * cannot be changed once an instance has been creased. - * - * @type {Array} - * @default Takes the value of `Responsive.breakpoints` - */ - breakpoints: Responsive.breakpoints, - - /** - * Enable / disable auto hiding calculations. It can help to increase - * performance slightly if you disable this option, but all columns would - * need to have breakpoint classes assigned to them - * - * @type {Boolean} - * @default `true` - */ - auto: true, - - /** - * Details control. If given as a string value, the `type` property of the - * default object is set to that value, and the defaults used for the rest - * of the object - this is for ease of implementation. - * - * The object consists of the following properties: - * - * * `display` - A function that is used to show and hide the hidden details - * * `renderer` - function that is called for display of the child row data. - * The default function will show the data from the hidden columns - * * `target` - Used as the selector for what objects to attach the child - * open / close to - * * `type` - `false` to disable the details display, `inline` or `column` - * for the two control types - * - * @type {Object|string} - */ - details: { - display: Responsive.display.childRow, - - renderer: Responsive.renderer.listHidden(), - - target: 0, - - type: 'inline' - }, - - /** - * Orthogonal data request option. This is used to define the data type - * requested when Responsive gets the data to show in the child row. - * - * @type {String} - */ - orthogonal: 'display' -}; - - -/* - * API - */ -var Api = $.fn.dataTable.Api; - -// Doesn't do anything - work around for a bug in DT... Not documented -Api.register( 'responsive()', function () { - return this; -} ); - -Api.register( 'responsive.index()', function ( li ) { - li = $(li); - - return { - column: li.data('dtr-index'), - row: li.parent().data('dtr-index') - }; -} ); - -Api.register( 'responsive.rebuild()', function () { - return this.iterator( 'table', function ( ctx ) { - if ( ctx._responsive ) { - ctx._responsive._classLogic(); - } - } ); -} ); - -Api.register( 'responsive.recalc()', function () { - return this.iterator( 'table', function ( ctx ) { - if ( ctx._responsive ) { - ctx._responsive._resizeAuto(); - ctx._responsive._resize(); - } - } ); -} ); - -Api.register( 'responsive.hasHidden()', function () { - var ctx = this.context[0]; - - return ctx._responsive ? - $.inArray( false, ctx._responsive.s.current ) !== -1 : - false; -} ); - - -/** - * Version information - * - * @name Responsive.version - * @static - */ -Responsive.version = '2.1.1'; - - -$.fn.dataTable.Responsive = Responsive; -$.fn.DataTable.Responsive = Responsive; - -// Attach a listener to the document which listens for DataTables initialisation -// events so we can automatically initialise -$(document).on( 'preInit.dt.dtr', function (e, settings, json) { - if ( e.namespace !== 'dt' ) { - return; - } - - if ( $(settings.nTable).hasClass( 'responsive' ) || - $(settings.nTable).hasClass( 'dt-responsive' ) || - settings.oInit.responsive || - DataTable.defaults.responsive - ) { - var init = settings.oInit.responsive; - - if ( init !== false ) { - new Responsive( settings, $.isPlainObject( init ) ? init : {} ); - } - } -} ); - - -return Responsive; -})); diff --git a/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/dataTables.responsive.min.js b/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/dataTables.responsive.min.js deleted file mode 100644 index 2bbfabbb..00000000 --- a/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/dataTables.responsive.min.js +++ /dev/null @@ -1,26 +0,0 @@ -/*! - Responsive 2.1.1 - 2014-2016 SpryMedia Ltd - datatables.net/license -*/ -(function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(l){return c(l,window,document)}):"object"===typeof exports?module.exports=function(l,k){l||(l=window);if(!k||!k.fn.dataTable)k=require("datatables.net")(l,k).$;return c(k,l,l.document)}:c(jQuery,window,document)})(function(c,l,k,p){var m=c.fn.dataTable,j=function(b,a){if(!m.versionCheck||!m.versionCheck("1.10.3"))throw"DataTables Responsive requires DataTables 1.10.3 or newer";this.s={dt:new m.Api(b),columns:[], -current:[]};this.s.dt.settings()[0].responsive||(a&&"string"===typeof a.details?a.details={type:a.details}:a&&!1===a.details?a.details={type:!1}:a&&!0===a.details&&(a.details={type:"inline"}),this.c=c.extend(!0,{},j.defaults,m.defaults.responsive,a),b.responsive=this,this._constructor())};c.extend(j.prototype,{_constructor:function(){var b=this,a=this.s.dt,d=a.settings()[0],e=c(l).width();a.settings()[0]._responsive=this;c(l).on("resize.dtr orientationchange.dtr",m.util.throttle(function(){var a= -c(l).width();a!==e&&(b._resize(),e=a)}));d.oApi._fnCallbackReg(d,"aoRowCreatedCallback",function(e){-1!==c.inArray(!1,b.s.current)&&c(">td, >th",e).each(function(e){e=a.column.index("toData",e);!1===b.s.current[e]&&c(this).css("display","none")})});a.on("destroy.dtr",function(){a.off(".dtr");c(a.table().body()).off(".dtr");c(l).off("resize.dtr orientationchange.dtr");c.each(b.s.current,function(a,e){!1===e&&b._setColumnVis(a,!0)})});this.c.breakpoints.sort(function(a,b){return a.width
-b.width?-1:0});this._classLogic();this._resizeAuto();d=this.c.details;!1!==d.type&&(b._detailsInit(),a.on("column-visibility.dtr",function(){b._classLogic();b._resizeAuto();b._resize()}),a.on("draw.dtr",function(){b._redrawChildren()}),c(a.table().node()).addClass("dtr-"+d.type));a.on("column-reorder.dtr",function(){b._classLogic();b._resizeAuto();b._resize()});a.on("column-sizing.dtr",function(){b._resizeAuto();b._resize()});a.on("preXhr.dtr",function(){var e=[];a.rows().every(function(){this.child.isShown()&& -e.push(this.id(true))});a.one("draw.dtr",function(){a.rows(e).every(function(){b._detailsDisplay(this,false)})})});a.on("init.dtr",function(){b._resizeAuto();b._resize();c.inArray(false,b.s.current)&&a.columns.adjust()});this._resize()},_columnsVisiblity:function(b){var a=this.s.dt,d=this.s.columns,e,f,g=d.map(function(a,b){return{columnIdx:b,priority:a.priority}}).sort(function(a,b){return a.priority!==b.priority?a.priority-b.priority:a.columnIdx-b.columnIdx}),h=c.map(d,function(a){return a.auto&& -null===a.minWidth?!1:!0===a.auto?"-":-1!==c.inArray(b,a.includeIn)}),n=0;e=0;for(f=h.length;e a-d[i].minWidth?(n=!0,h[i]=!1):h[i]=!0,a-=d[i].minWidth)}g=!1;e=0;for(f=d.length;e =g&&f(c,a[d].name)}else{if("not-"===i){d=0;for(i=a.length;d").append(h).appendTo(f)}c(" ").append(g).appendTo(e);"inline"===this.c.details.type&&c(d).addClass("dtr-inline collapsed");c(d).find("[name]").removeAttr("name");d=c("").css({width:1,height:1,overflow:"hidden"}).append(d);d.insertBefore(b.table().node());g.each(function(c){c=b.column.index("fromVisible",c);a[c].minWidth=this.offsetWidth||0});d.remove()}},_setColumnVis:function(b, -a){var d=this.s.dt,e=a?"":"none";c(d.column(b).header()).css("display",e);c(d.column(b).footer()).css("display",e);d.column(b).nodes().to$().css("display",e)},_tabIndexes:function(){var b=this.s.dt,a=b.cells({page:"current"}).nodes().to$(),d=b.settings()[0],e=this.c.details.target;a.filter("[data-dtr-keyboard]").removeData("[data-dtr-keyboard]");a="number"===typeof e?":eq("+e+")":e;"td:first-child, th:first-child"===a&&(a=">td:first-child, >th:first-child");c(a,b.rows({page:"current"}).nodes()).attr("tabIndex", -d.iTabIndex).data("dtr-keyboard",1)}});j.breakpoints=[{name:"desktop",width:Infinity},{name:"tablet-l",width:1024},{name:"tablet-p",width:768},{name:"mobile-l",width:480},{name:"mobile-p",width:320}];j.display={childRow:function(b,a,d){if(a){if(c(b.node()).hasClass("parent"))return b.child(d(),"child").show(),!0}else{if(b.child.isShown())return b.child(!1),c(b.node()).removeClass("parent"),!1;b.child(d(),"child").show();c(b.node()).addClass("parent");return!0}},childRowImmediate:function(b,a,d){if(!a&& -b.child.isShown()||!b.responsive.hasHidden())return b.child(!1),c(b.node()).removeClass("parent"),!1;b.child(d(),"child").show();c(b.node()).addClass("parent");return!0},modal:function(b){return function(a,d,e){if(d)c("div.dtr-modal-content").empty().append(e());else{var f=function(){g.remove();c(k).off("keypress.dtr")},g=c('').append(c('').append(c('').append(e())).append(c(' ×').click(function(){f()}))).append(c('').click(function(){f()})).appendTo("body"); -c(k).on("keyup.dtr",function(a){27===a.keyCode&&(a.stopPropagation(),f())})}b&&b.header&&c("div.dtr-modal-content").prepend(""+b.header(a)+"
")}}};j.renderer={listHidden:function(){return function(b,a,d){return(b=c.map(d,function(a){return a.hidden?'- '+a.title+' '+a.data+"
":""}).join(""))?c('').append(b): -!1}},tableAll:function(b){b=c.extend({tableClass:""},b);return function(a,d,e){a=c.map(e,function(a){return'
"}).join("");return c(' '+a.title+": "+a.data+" ').append(a)}}};j.defaults={breakpoints:j.breakpoints,auto:!0,details:{display:j.display.childRow,renderer:j.renderer.listHidden(),target:0,type:"inline"},orthogonal:"display"};var o=c.fn.dataTable.Api; -o.register("responsive()",function(){return this});o.register("responsive.index()",function(b){b=c(b);return{column:b.data("dtr-index"),row:b.parent().data("dtr-index")}});o.register("responsive.rebuild()",function(){return this.iterator("table",function(b){b._responsive&&b._responsive._classLogic()})});o.register("responsive.recalc()",function(){return this.iterator("table",function(b){b._responsive&&(b._responsive._resizeAuto(),b._responsive._resize())})});o.register("responsive.hasHidden()",function(){var b= -this.context[0];return b._responsive?-1!==c.inArray(!1,b._responsive.s.current):!1});j.version="2.1.1";c.fn.dataTable.Responsive=j;c.fn.DataTable.Responsive=j;c(k).on("preInit.dt.dtr",function(b,a){if("dt"===b.namespace&&(c(a.nTable).hasClass("responsive")||c(a.nTable).hasClass("dt-responsive")||a.oInit.responsive||m.defaults.responsive)){var d=a.oInit.responsive;!1!==d&&new j(a,c.isPlainObject(d)?d:{})}});return j}); diff --git a/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/datatables-all.js b/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/datatables-all.js deleted file mode 100644 index 378deb62..00000000 --- a/wp/wp-content/plugins/ip-geo-block/admin/datatables/js/datatables-all.js +++ /dev/null @@ -1,17649 +0,0 @@ -/*! DataTables 1.10.16 - * 2008-2017 SpryMedia Ltd - datatables.net/license - */ - -/** - * @summary DataTables - * @description Paginate, search and order HTML tables - * @version 1.10.16 - * @file jquery.dataTables.js - * @author SpryMedia Ltd - * @contact www.datatables.net - * @copyright Copyright 2008-2017 SpryMedia Ltd. - * - * This source file is free software, available under the following license: - * MIT license - https://datatables.net/license - * - * This source file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. - * - * For details please refer to: https://www.datatables.net - */ - -/*jslint evil: true, undef: true, browser: true */ -/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/ - -(function( factory ) { - "use strict"; - - if ( typeof define === 'function' && define.amd ) { - // AMD - define( ['jquery'], function ( $ ) { - return factory( $, window, document ); - } ); - } - else if ( typeof exports === 'object' ) { - // CommonJS - module.exports = function (root, $) { - if ( ! root ) { - // CommonJS environments without a window global must pass a - // root. This will give an error otherwise - root = window; - } - - if ( ! $ ) { - $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window - require('jquery') : - require('jquery')( root ); - } - - return factory( $, root, root.document ); - }; - } - else { - // Browser - factory( jQuery, window, document ); - } -} -(function( $, window, document, undefined ) { - "use strict"; - - /** - * DataTables is a plug-in for the jQuery Javascript library. It is a highly - * flexible tool, based upon the foundations of progressive enhancement, - * which will add advanced interaction controls to any HTML table. For a - * full list of features please refer to - * [DataTables.net](href="https://datatables.net). - * - * Note that the `DataTable` object is not a global variable but is aliased - * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may - * be accessed. - * - * @class - * @param {object} [init={}] Configuration object for DataTables. Options - * are defined by {@link DataTable.defaults} - * @requires jQuery 1.7+ - * - * @example - * // Basic initialisation - * $(document).ready( function { - * $('#example').dataTable(); - * } ); - * - * @example - * // Initialisation with configuration options - in this case, disable - * // pagination and sorting. - * $(document).ready( function { - * $('#example').dataTable( { - * "paginate": false, - * "sort": false - * } ); - * } ); - */ - var DataTable = function ( options ) - { - /** - * Perform a jQuery selector action on the table's TR elements (from the tbody) and - * return the resulting jQuery object. - * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on - * @param {object} [oOpts] Optional parameters for modifying the rows to be included - * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter - * criterion ("applied") or all TR elements (i.e. no filter). - * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. - * Can be either 'current', whereby the current sorting of the table is used, or - * 'original' whereby the original order the data was read into the table is used. - * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page - * ("current") or not ("all"). If 'current' is given, then order is assumed to be - * 'current' and filter is 'applied', regardless of what they might be given as. - * @returns {object} jQuery object, filtered by the given selector. - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * - * // Highlight every second row - * oTable.$('tr:odd').css('backgroundColor', 'blue'); - * } ); - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * - * // Filter to rows with 'Webkit' in them, add a background colour and then - * // remove the filter, thus highlighting the 'Webkit' rows only. - * oTable.fnFilter('Webkit'); - * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue'); - * oTable.fnFilter(''); - * } ); - */ - this.$ = function ( sSelector, oOpts ) - { - return this.api(true).$( sSelector, oOpts ); - }; - - - /** - * Almost identical to $ in operation, but in this case returns the data for the matched - * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes - * rather than any descendants, so the data can be obtained for the row/cell. If matching - * rows are found, the data returned is the original data array/object that was used to - * create the row (or a generated array if from a DOM source). - * - * This method is often useful in-combination with $ where both functions are given the - * same parameters and the array indexes will match identically. - * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on - * @param {object} [oOpts] Optional parameters for modifying the rows to be included - * @param {string} [oOpts.filter=none] Select elements that meet the current filter - * criterion ("applied") or all elements (i.e. no filter). - * @param {string} [oOpts.order=current] Order of the data in the processed array. - * Can be either 'current', whereby the current sorting of the table is used, or - * 'original' whereby the original order the data was read into the table is used. - * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page - * ("current") or not ("all"). If 'current' is given, then order is assumed to be - * 'current' and filter is 'applied', regardless of what they might be given as. - * @returns {array} Data for the matched elements. If any elements, as a result of the - * selector, were not TR, TD or TH elements in the DataTable, they will have a null - * entry in the array. - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * - * // Get the data from the first row in the table - * var data = oTable._('tr:first'); - * - * // Do something useful with the data - * alert( "First cell is: "+data[0] ); - * } ); - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * - * // Filter to 'Webkit' and get all data for - * oTable.fnFilter('Webkit'); - * var data = oTable._('tr', {"search": "applied"}); - * - * // Do something with the data - * alert( data.length+" rows matched the search" ); - * } ); - */ - this._ = function ( sSelector, oOpts ) - { - return this.api(true).rows( sSelector, oOpts ).data(); - }; - - - /** - * Create a DataTables Api instance, with the currently selected tables for - * the Api's context. - * @param {boolean} [traditional=false] Set the API instance's context to be - * only the table referred to by the `DataTable.ext.iApiIndex` option, as was - * used in the API presented by DataTables 1.9- (i.e. the traditional mode), - * or if all tables captured in the jQuery object should be used. - * @return {DataTables.Api} - */ - this.api = function ( traditional ) - { - return traditional ? - new _Api( - _fnSettingsFromNode( this[ _ext.iApiIndex ] ) - ) : - new _Api( this ); - }; - - - /** - * Add a single new row or multiple rows of data to the table. Please note - * that this is suitable for client-side processing only - if you are using - * server-side processing (i.e. "bServerSide": true), then to add data, you - * must add it to the data source, i.e. the server-side, through an Ajax call. - * @param {array|object} data The data to be added to the table. This can be: - *
- *
- * @param {bool} [redraw=true] redraw the table or not - * @returns {array} An array of integers, representing the list of indexes in - * aoData ({@link DataTable.models.oSettings}) that have been added to - * the table. - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * // Global var for counter - * var giCount = 2; - * - * $(document).ready(function() { - * $('#example').dataTable(); - * } ); - * - * function fnClickAddRow() { - * $('#example').dataTable().fnAddData( [ - * giCount+".1", - * giCount+".2", - * giCount+".3", - * giCount+".4" ] - * ); - * - * giCount++; - * } - */ - this.fnAddData = function( data, redraw ) - { - var api = this.api( true ); - - /* Check if we want to add multiple rows or not */ - var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ? - api.rows.add( data ) : - api.row.add( data ); - - if ( redraw === undefined || redraw ) { - api.draw(); - } - - return rows.flatten().toArray(); - }; - - - /** - * This function will make DataTables recalculate the column sizes, based on the data - * contained in the table and the sizes applied to the columns (in the DOM, CSS or - * through the sWidth parameter). This can be useful when the width of the table's - * parent element changes (for example a window resize). - * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable( { - * "sScrollY": "200px", - * "bPaginate": false - * } ); - * - * $(window).on('resize', function () { - * oTable.fnAdjustColumnSizing(); - * } ); - * } ); - */ - this.fnAdjustColumnSizing = function ( bRedraw ) - { - var api = this.api( true ).columns.adjust(); - var settings = api.settings()[0]; - var scroll = settings.oScroll; - - if ( bRedraw === undefined || bRedraw ) { - api.draw( false ); - } - else if ( scroll.sX !== "" || scroll.sY !== "" ) { - /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */ - _fnScrollDraw( settings ); - } - }; - - - /** - * Quickly and simply clear a table - * @param {bool} [bRedraw=true] redraw the table or not - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * - * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...) - * oTable.fnClearTable(); - * } ); - */ - this.fnClearTable = function( bRedraw ) - { - var api = this.api( true ).clear(); - - if ( bRedraw === undefined || bRedraw ) { - api.draw(); - } - }; - - - /** - * The exact opposite of 'opening' a row, this function will close any rows which - * are currently 'open'. - * @param {node} nTr the table row to 'close' - * @returns {int} 0 on success, or 1 if failed (can't find the row) - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable; - * - * // 'open' an information row when a row is clicked on - * $('#example tbody tr').click( function () { - * if ( oTable.fnIsOpen(this) ) { - * oTable.fnClose( this ); - * } else { - * oTable.fnOpen( this, "Temporary row opened", "info_row" ); - * } - * } ); - * - * oTable = $('#example').dataTable(); - * } ); - */ - this.fnClose = function( nTr ) - { - this.api( true ).row( nTr ).child.hide(); - }; - - - /** - * Remove a row for the table - * @param {mixed} target The index of the row from aoData to be deleted, or - * the TR element you want to delete - * @param {function|null} [callBack] Callback function - * @param {bool} [redraw=true] Redraw the table or not - * @returns {array} The row that was deleted - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * - * // Immediately remove the first row - * oTable.fnDeleteRow( 0 ); - * } ); - */ - this.fnDeleteRow = function( target, callback, redraw ) - { - var api = this.api( true ); - var rows = api.rows( target ); - var settings = rows.settings()[0]; - var data = settings.aoData[ rows[0][0] ]; - - rows.remove(); - - if ( callback ) { - callback.call( this, settings, data ); - } - - if ( redraw === undefined || redraw ) { - api.draw(); - } - - return data; - }; - - - /** - * Restore the table to it's original state in the DOM by removing all of DataTables - * enhancements, alterations to the DOM structure of the table and event listeners. - * @param {boolean} [remove=false] Completely remove the table from the DOM - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * // This example is fairly pointless in reality, but shows how fnDestroy can be used - * var oTable = $('#example').dataTable(); - * oTable.fnDestroy(); - * } ); - */ - this.fnDestroy = function ( remove ) - { - this.api( true ).destroy( remove ); - }; - - - /** - * Redraw the table - * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw. - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * - * // Re-draw the table - you wouldn't want to do it here, but it's an example :-) - * oTable.fnDraw(); - * } ); - */ - this.fnDraw = function( complete ) - { - // Note that this isn't an exact match to the old call to _fnDraw - it takes - // into account the new data, but can hold position. - this.api( true ).draw( complete ); - }; - - - /** - * Filter the input based on data - * @param {string} sInput String to filter the table on - * @param {int|null} [iColumn] Column to limit filtering to - * @param {bool} [bRegex=false] Treat as regular expression or not - * @param {bool} [bSmart=true] Perform smart filtering or not - * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es) - * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false) - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * - * // Sometime later - filter... - * oTable.fnFilter( 'test string' ); - * } ); - */ - this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive ) - { - var api = this.api( true ); - - if ( iColumn === null || iColumn === undefined ) { - api.search( sInput, bRegex, bSmart, bCaseInsensitive ); - } - else { - api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive ); - } - - api.draw(); - }; - - - /** - * Get the data for the whole table, an individual row or an individual cell based on the - * provided parameters. - * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as - * a TR node then the data source for the whole row will be returned. If given as a - * TD/TH cell node then iCol will be automatically calculated and the data for the - * cell returned. If given as an integer, then this is treated as the aoData internal - * data index for the row (see fnGetPosition) and the data for that row used. - * @param {int} [col] Optional column index that you want the data of. - * @returns {array|object|string} If mRow is undefined, then the data for all rows is - * returned. If mRow is defined, just data for that row, and is iCol is - * defined, only data for the designated cell is returned. - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * // Row data - * $(document).ready(function() { - * oTable = $('#example').dataTable(); - * - * oTable.$('tr').click( function () { - * var data = oTable.fnGetData( this ); - * // ... do something with the array / object of data for the row - * } ); - * } ); - * - * @example - * // Individual cell data - * $(document).ready(function() { - * oTable = $('#example').dataTable(); - * - * oTable.$('td').click( function () { - * var sData = oTable.fnGetData( this ); - * alert( 'The cell clicked on had the value of '+sData ); - * } ); - * } ); - */ - this.fnGetData = function( src, col ) - { - var api = this.api( true ); - - if ( src !== undefined ) { - var type = src.nodeName ? src.nodeName.toLowerCase() : ''; - - return col !== undefined || type == 'td' || type == 'th' ? - api.cell( src, col ).data() : - api.row( src ).data() || null; - } - - return api.data().toArray(); - }; - - - /** - * Get an array of the TR nodes that are used in the table's body. Note that you will - * typically want to use the '$' API method in preference to this as it is more - * flexible. - * @param {int} [iRow] Optional row index for the TR element you want - * @returns {array|node} If iRow is undefined, returns an array of all TR elements - * in the table's body, or iRow is defined, just the TR element requested. - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * - * // Get the nodes from the table - * var nNodes = oTable.fnGetNodes( ); - * } ); - */ - this.fnGetNodes = function( iRow ) - { - var api = this.api( true ); - - return iRow !== undefined ? - api.row( iRow ).node() : - api.rows().nodes().flatten().toArray(); - }; - - - /** - * Get the array indexes of a particular cell from it's DOM element - * and column index including hidden columns - * @param {node} node this can either be a TR, TD or TH in the table's body - * @returns {int} If nNode is given as a TR, then a single index is returned, or - * if given as a cell, an array of [row index, column index (visible), - * column index (all)] is given. - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * $('#example tbody td').click( function () { - * // Get the position of the current data from the node - * var aPos = oTable.fnGetPosition( this ); - * - * // Get the data array for this row - * var aData = oTable.fnGetData( aPos[0] ); - * - * // Update the data array and return the value - * aData[ aPos[1] ] = 'clicked'; - * this.innerHTML = 'clicked'; - * } ); - * - * // Init DataTables - * oTable = $('#example').dataTable(); - * } ); - */ - this.fnGetPosition = function( node ) - { - var api = this.api( true ); - var nodeName = node.nodeName.toUpperCase(); - - if ( nodeName == 'TR' ) { - return api.row( node ).index(); - } - else if ( nodeName == 'TD' || nodeName == 'TH' ) { - var cell = api.cell( node ).index(); - - return [ - cell.row, - cell.columnVisible, - cell.column - ]; - } - return null; - }; - - - /** - * Check to see if a row is 'open' or not. - * @param {node} nTr the table row to check - * @returns {boolean} true if the row is currently open, false otherwise - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable; - * - * // 'open' an information row when a row is clicked on - * $('#example tbody tr').click( function () { - * if ( oTable.fnIsOpen(this) ) { - * oTable.fnClose( this ); - * } else { - * oTable.fnOpen( this, "Temporary row opened", "info_row" ); - * } - * } ); - * - * oTable = $('#example').dataTable(); - * } ); - */ - this.fnIsOpen = function( nTr ) - { - return this.api( true ).row( nTr ).child.isShown(); - }; - - - /** - * This function will place a new row directly after a row which is currently - * on display on the page, with the HTML contents that is passed into the - * function. This can be used, for example, to ask for confirmation that a - * particular record should be deleted. - * @param {node} nTr The table row to 'open' - * @param {string|node|jQuery} mHtml The HTML to put into the row - * @param {string} sClass Class to give the new TD cell - * @returns {node} The row opened. Note that if the table row passed in as the - * first parameter, is not found in the table, this method will silently - * return. - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable; - * - * // 'open' an information row when a row is clicked on - * $('#example tbody tr').click( function () { - * if ( oTable.fnIsOpen(this) ) { - * oTable.fnClose( this ); - * } else { - * oTable.fnOpen( this, "Temporary row opened", "info_row" ); - * } - * } ); - * - * oTable = $('#example').dataTable(); - * } ); - */ - this.fnOpen = function( nTr, mHtml, sClass ) - { - return this.api( true ) - .row( nTr ) - .child( mHtml, sClass ) - .show() - .child()[0]; - }; - - - /** - * Change the pagination - provides the internal logic for pagination in a simple API - * function. With this function you can have a DataTables table go to the next, - * previous, first or last pages. - * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" - * or page number to jump to (integer), note that page 0 is the first page. - * @param {bool} [bRedraw=true] Redraw the table or not - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * oTable.fnPageChange( 'next' ); - * } ); - */ - this.fnPageChange = function ( mAction, bRedraw ) - { - var api = this.api( true ).page( mAction ); - - if ( bRedraw === undefined || bRedraw ) { - api.draw(false); - } - }; - - - /** - * Show a particular column - * @param {int} iCol The column whose display should be changed - * @param {bool} bShow Show (true) or hide (false) the column - * @param {bool} [bRedraw=true] Redraw the table or not - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * - * // Hide the second column after initialisation - * oTable.fnSetColumnVis( 1, false ); - * } ); - */ - this.fnSetColumnVis = function ( iCol, bShow, bRedraw ) - { - var api = this.api( true ).column( iCol ).visible( bShow ); - - if ( bRedraw === undefined || bRedraw ) { - api.columns.adjust().draw(); - } - }; - - - /** - * Get the settings for a particular table for external manipulation - * @returns {object} DataTables settings object. See - * {@link DataTable.models.oSettings} - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * var oSettings = oTable.fnSettings(); - * - * // Show an example parameter from the settings - * alert( oSettings._iDisplayStart ); - * } ); - */ - this.fnSettings = function() - { - return _fnSettingsFromNode( this[_ext.iApiIndex] ); - }; - - - /** - * Sort the table by a particular column - * @param {int} iCol the data index to sort on. Note that this will not match the - * 'display index' if you have hidden data entries - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * - * // Sort immediately with columns 0 and 1 - * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] ); - * } ); - */ - this.fnSort = function( aaSort ) - { - this.api( true ).order( aaSort ).draw(); - }; - - - /** - * Attach a sort listener to an element for a given column - * @param {node} nNode the element to attach the sort listener to - * @param {int} iColumn the column that a click on this node will sort on - * @param {function} [fnCallback] callback function when sort is run - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * - * // Sort on column 1, when 'sorter' is clicked on - * oTable.fnSortListener( document.getElementById('sorter'), 1 ); - * } ); - */ - this.fnSortListener = function( nNode, iColumn, fnCallback ) - { - this.api( true ).order.listener( nNode, iColumn, fnCallback ); - }; - - - /** - * Update a table cell or row - this method will accept either a single value to - * update the cell with, an array of values with one element for each column or - * an object in the same format as the original data source. The function is - * self-referencing in order to make the multi column updates easier. - * @param {object|array|string} mData Data to update the cell/row with - * @param {node|int} mRow TR element you want to update or the aoData index - * @param {int} [iColumn] The column to update, give as null or undefined to - * update a whole row. - * @param {bool} [bRedraw=true] Redraw the table or not - * @param {bool} [bAction=true] Perform pre-draw actions or not - * @returns {int} 0 on success, 1 on error - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell - * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row - * } ); - */ - this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction ) - { - var api = this.api( true ); - - if ( iColumn === undefined || iColumn === null ) { - api.row( mRow ).data( mData ); - } - else { - api.cell( mRow, iColumn ).data( mData ); - } - - if ( bAction === undefined || bAction ) { - api.columns.adjust(); - } - - if ( bRedraw === undefined || bRedraw ) { - api.draw(); - } - return 0; - }; - - - /** - * Provide a common method for plug-ins to check the version of DataTables being used, in order - * to ensure compatibility. - * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the - * formats "X" and "X.Y" are also acceptable. - * @returns {boolean} true if this version of DataTables is greater or equal to the required - * version, or false if this version of DataTales is not suitable - * @method - * @dtopt API - * @deprecated Since v1.10 - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * alert( oTable.fnVersionCheck( '1.9.0' ) ); - * } ); - */ - this.fnVersionCheck = _ext.fnVersionCheck; - - - var _that = this; - var emptyInit = options === undefined; - var len = this.length; - - if ( emptyInit ) { - options = {}; - } - - this.oApi = this.internal = _ext.internal; - - // Extend with old style plug-in API methods - for ( var fn in DataTable.ext.internal ) { - if ( fn ) { - this[fn] = _fnExternApiFunc(fn); - } - } - - this.each(function() { - // For each initialisation we want to give it a clean initialisation - // object that can be bashed around - var o = {}; - var oInit = len > 1 ? // optimisation for single table case - _fnExtend( o, options, true ) : - options; - - /*global oInit,_that,emptyInit*/ - var i=0, iLen, j, jLen, k, kLen; - var sId = this.getAttribute( 'id' ); - var bInitHandedOff = false; - var defaults = DataTable.defaults; - var $this = $(this); - - - /* Sanity check */ - if ( this.nodeName.toLowerCase() != 'table' ) - { - _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 ); - return; - } - - /* Backwards compatibility for the defaults */ - _fnCompatOpts( defaults ); - _fnCompatCols( defaults.column ); - - /* Convert the camel-case defaults to Hungarian */ - _fnCamelToHungarian( defaults, defaults, true ); - _fnCamelToHungarian( defaults.column, defaults.column, true ); - - /* Setting up the initialisation object */ - _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) ); - - - - /* Check to see if we are re-initialising a table */ - var allSettings = DataTable.settings; - for ( i=0, iLen=allSettings.length ; i- 1D array of data - add a single row with the data provided
- *- 2D array of arrays - add multiple rows in a single call
- *- object - data object when using mData
- *- array of objects - multiple data objects when using mData
- *').appendTo($this); - } - oSettings.nTHead = thead[0]; - - var tbody = $this.children('tbody'); - if ( tbody.length === 0 ) { - tbody = $('').appendTo($this); - } - oSettings.nTBody = tbody[0]; - - var tfoot = $this.children('tfoot'); - if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) { - // If we are a scrolling table, and no footer has been given, then we need to create - // a tfoot element for the caption element to be appended to - tfoot = $('').appendTo($this); - } - - if ( tfoot.length === 0 || tfoot.children().length === 0 ) { - $this.addClass( oClasses.sNoFooter ); - } - else if ( tfoot.length > 0 ) { - oSettings.nTFoot = tfoot[0]; - _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot ); - } - - /* Check if there is data passing into the constructor */ - if ( oInit.aaData ) { - for ( i=0 ; i /g; - - // This is not strict ISO8601 - Date.parse() is quite lax, although - // implementations differ between browsers. - var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/; - - // Escape regular expression special characters - var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); - - // https://en.wikipedia.org/wiki/Foreign_exchange_market - // - \u20BD - Russian ruble. - // - \u20a9 - South Korean Won - // - \u20BA - Turkish Lira - // - \u20B9 - Indian Rupee - // - R - Brazil (R$) and South Africa - // - fr - Swiss Franc - // - kr - Swedish krona, Norwegian krone and Danish krone - // - \u2009 is thin space and \u202F is narrow no-break space, both used in many - // standards as thousands separators. - var _re_formatted_numeric = /[',$ツ」竄ャツ・%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi; - - - var _empty = function ( d ) { - return !d || d === true || d === '-' ? true : false; - }; - - - var _intVal = function ( s ) { - var integer = parseInt( s, 10 ); - return !isNaN(integer) && isFinite(s) ? integer : null; - }; - - // Convert from a formatted number with characters other than `.` as the - // decimal place, to a Javascript number - var _numToDecimal = function ( num, decimalPoint ) { - // Cache created regular expressions for speed as this function is called often - if ( ! _re_dic[ decimalPoint ] ) { - _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); - } - return typeof num === 'string' && decimalPoint !== '.' ? - num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : - num; - }; - - - var _isNumber = function ( d, decimalPoint, formatted ) { - var strType = typeof d === 'string'; - - // If empty return immediately so there must be a number if it is a - // formatted string (this stops the string "k", or "kr", etc being detected - // as a formatted number for currency - if ( _empty( d ) ) { - return true; - } - - if ( decimalPoint && strType ) { - d = _numToDecimal( d, decimalPoint ); - } - - if ( formatted && strType ) { - d = d.replace( _re_formatted_numeric, '' ); - } - - return !isNaN( parseFloat(d) ) && isFinite( d ); - }; - - - // A string without HTML in it can be considered to be HTML still - var _isHtml = function ( d ) { - return _empty( d ) || typeof d === 'string'; - }; - - - var _htmlNumeric = function ( d, decimalPoint, formatted ) { - if ( _empty( d ) ) { - return true; - } - - var html = _isHtml( d ); - return ! html ? - null : - _isNumber( _stripHtml( d ), decimalPoint, formatted ) ? - true : - null; - }; - - - var _pluck = function ( a, prop, prop2 ) { - var out = []; - var i=0, ien=a.length; - - // Could have the test in the loop for slightly smaller code, but speed - // is essential here - if ( prop2 !== undefined ) { - for ( ; i ') - .css( { - position: 'fixed', - top: 0, - left: $(window).scrollLeft()*-1, // allow for scrolling - height: 1, - width: 1, - overflow: 'hidden' - } ) - .append( - $('') - .css( { - position: 'absolute', - top: 1, - left: 1, - width: 100, - overflow: 'scroll' - } ) - .append( - $('') - .css( { - width: '100%', - height: 10 - } ) - ) - ) - .appendTo( 'body' ); - - var outer = n.children(); - var inner = outer.children(); - - // Numbers below, in order, are: - // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth - // - // IE6 XP: 100 100 100 83 - // IE7 Vista: 100 100 100 83 - // IE 8+ Windows: 83 83 100 83 - // Evergreen Windows: 83 83 100 83 - // Evergreen Mac with scrollbars: 85 85 100 85 - // Evergreen Mac without scrollbars: 100 100 100 100 - - // Get scrollbar width - browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth; - - // IE6/7 will oversize a width 100% element inside a scrolling element, to - // include the width of the scrollbar, while other browsers ensure the inner - // element is contained without forcing scrolling - browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100; - - // In rtl text layout, some browsers (most, but not all) will place the - // scrollbar on the left, rather than the right. - browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1; - - // IE8- don't provide height and width for getBoundingClientRect - browser.bBounding = n[0].getBoundingClientRect().width ? true : false; - - n.remove(); - } - - $.extend( settings.oBrowser, DataTable.__browser ); - settings.oScroll.iBarWidth = DataTable.__browser.barWidth; - } - - - /** - * Array.prototype reduce[Right] method, used for browsers which don't support - * JS 1.6. Done this way to reduce code size, since we iterate either way - * @param {object} settings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnReduce ( that, fn, init, start, end, inc ) - { - var - i = start, - value, - isSet = false; - - if ( init !== undefined ) { - value = init; - isSet = true; - } - - while ( i !== end ) { - if ( ! that.hasOwnProperty(i) ) { - continue; - } - - value = isSet ? - fn( value, that[i], i, that ) : - that[i]; - - isSet = true; - i += inc; - } - - return value; - } - - /** - * Add a column to the list used for the table with default values - * @param {object} oSettings dataTables settings object - * @param {node} nTh The th element for this column - * @memberof DataTable#oApi - */ - function _fnAddColumn( oSettings, nTh ) - { - // Add column to aoColumns array - var oDefaults = DataTable.defaults.column; - var iCol = oSettings.aoColumns.length; - var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { - "nTh": nTh ? nTh : document.createElement('th'), - "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', - "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], - "mData": oDefaults.mData ? oDefaults.mData : iCol, - idx: iCol - } ); - oSettings.aoColumns.push( oCol ); - - // Add search object for column specific search. Note that the `searchCols[ iCol ]` - // passed into extend can be undefined. This allows the user to give a default - // with only some of the parameters defined, and also not give a default - var searchCols = oSettings.aoPreSearchCols; - searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); - - // Use the default column options function to initialise classes etc - _fnColumnOptions( oSettings, iCol, $(nTh).data() ); - } - - - /** - * Apply options for a column - * @param {object} oSettings dataTables settings object - * @param {int} iCol column index to consider - * @param {object} oOptions object with sType, bVisible and bSearchable etc - * @memberof DataTable#oApi - */ - function _fnColumnOptions( oSettings, iCol, oOptions ) - { - var oCol = oSettings.aoColumns[ iCol ]; - var oClasses = oSettings.oClasses; - var th = $(oCol.nTh); - - // Try to get width information from the DOM. We can't get it from CSS - // as we'd need to parse the CSS stylesheet. `width` option can override - if ( ! oCol.sWidthOrig ) { - // Width attribute - oCol.sWidthOrig = th.attr('width') || null; - - // Style attribute - var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); - if ( t ) { - oCol.sWidthOrig = t[1]; - } - } - - /* User specified column options */ - if ( oOptions !== undefined && oOptions !== null ) - { - // Backwards compatibility - _fnCompatCols( oOptions ); - - // Map camel case parameters to their Hungarian counterparts - _fnCamelToHungarian( DataTable.defaults.column, oOptions ); - - /* Backwards compatibility for mDataProp */ - if ( oOptions.mDataProp !== undefined && !oOptions.mData ) - { - oOptions.mData = oOptions.mDataProp; - } - - if ( oOptions.sType ) - { - oCol._sManualType = oOptions.sType; - } - - // `class` is a reserved word in Javascript, so we need to provide - // the ability to use a valid name for the camel case input - if ( oOptions.className && ! oOptions.sClass ) - { - oOptions.sClass = oOptions.className; - } - if ( oOptions.sClass ) { - th.addClass( oOptions.sClass ); - } - - $.extend( oCol, oOptions ); - _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); - - /* iDataSort to be applied (backwards compatibility), but aDataSort will take - * priority if defined - */ - if ( oOptions.iDataSort !== undefined ) - { - oCol.aDataSort = [ oOptions.iDataSort ]; - } - _fnMap( oCol, oOptions, "aDataSort" ); - } - - /* Cache the data get and set functions for speed */ - var mDataSrc = oCol.mData; - var mData = _fnGetObjectDataFn( mDataSrc ); - var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; - - var attrTest = function( src ) { - return typeof src === 'string' && src.indexOf('@') !== -1; - }; - oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( - attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) - ); - oCol._setter = null; - - oCol.fnGetData = function (rowData, type, meta) { - var innerData = mData( rowData, type, undefined, meta ); - - return mRender && type ? - mRender( innerData, type, rowData, meta ) : - innerData; - }; - oCol.fnSetData = function ( rowData, val, meta ) { - return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); - }; - - // Indicate if DataTables should read DOM data as an object or array - // Used in _fnGetRowElements - if ( typeof mDataSrc !== 'number' ) { - oSettings._rowReadObject = true; - } - - /* Feature sorting overrides column specific when off */ - if ( !oSettings.oFeatures.bSort ) - { - oCol.bSortable = false; - th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called - } - - /* Check that the class assignment is correct for sorting */ - var bAsc = $.inArray('asc', oCol.asSorting) !== -1; - var bDesc = $.inArray('desc', oCol.asSorting) !== -1; - if ( !oCol.bSortable || (!bAsc && !bDesc) ) - { - oCol.sSortingClass = oClasses.sSortableNone; - oCol.sSortingClassJUI = ""; - } - else if ( bAsc && !bDesc ) - { - oCol.sSortingClass = oClasses.sSortableAsc; - oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; - } - else if ( !bAsc && bDesc ) - { - oCol.sSortingClass = oClasses.sSortableDesc; - oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; - } - else - { - oCol.sSortingClass = oClasses.sSortable; - oCol.sSortingClassJUI = oClasses.sSortJUI; - } - } - - - /** - * Adjust the table column widths for new data. Note: you would probably want to - * do a redraw after calling this function! - * @param {object} settings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnAdjustColumnSizing ( settings ) - { - /* Not interested in doing column width calculation if auto-width is disabled */ - if ( settings.oFeatures.bAutoWidth !== false ) - { - var columns = settings.aoColumns; - - _fnCalculateColumnWidths( settings ); - for ( var i=0 , iLen=columns.length ; i =0 ; i-- ) - { - def = aoColDefs[i]; - - /* Each definition can target multiple columns, as it is an array */ - var aTargets = def.targets !== undefined ? - def.targets : - def.aTargets; - - if ( ! $.isArray( aTargets ) ) - { - aTargets = [ aTargets ]; - } - - for ( j=0, jLen=aTargets.length ; j = 0 ) - { - /* Add columns that we don't yet know about */ - while( columns.length <= aTargets[j] ) - { - _fnAddColumn( oSettings ); - } - - /* Integer, basic index */ - fn( aTargets[j], def ); - } - else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 ) - { - /* Negative integer, right to left column counting */ - fn( columns.length+aTargets[j], def ); - } - else if ( typeof aTargets[j] === 'string' ) - { - /* Class name matching on TH element */ - for ( k=0, kLen=columns.length ; k =0 if successful (index of new aoData entry), -1 if failed - * @memberof DataTable#oApi - */ - function _fnAddData ( oSettings, aDataIn, nTr, anTds ) - { - /* Create the object for storing information about this new row */ - var iRow = oSettings.aoData.length; - var oData = $.extend( true, {}, DataTable.models.oRow, { - src: nTr ? 'dom' : 'data', - idx: iRow - } ); - - oData._aData = aDataIn; - oSettings.aoData.push( oData ); - - /* Create the cells */ - var nTd, sThisType; - var columns = oSettings.aoColumns; - - // Invalidate the column types as the new data needs to be revalidated - for ( var i=0, iLen=columns.length ; i iTarget ) - { - a[i]--; - } - } - - if ( iTargetIndex != -1 && splice === undefined ) - { - a.splice( iTargetIndex, 1 ); - } - } - - - /** - * Mark cached data as invalid such that a re-read of the data will occur when - * the cached data is next requested. Also update from the data source object. - * - * @param {object} settings DataTables settings object - * @param {int} rowIdx Row index to invalidate - * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom' - * or 'data' - * @param {int} [colIdx] Column index to invalidate. If undefined the whole - * row will be invalidated - * @memberof DataTable#oApi - * - * @todo For the modularisation of v1.11 this will need to become a callback, so - * the sort and filter methods can subscribe to it. That will required - * initialisation options for sorting, which is why it is not already baked in - */ - function _fnInvalidate( settings, rowIdx, src, colIdx ) - { - var row = settings.aoData[ rowIdx ]; - var i, ien; - var cellWrite = function ( cell, col ) { - // This is very frustrating, but in IE if you just write directly - // to innerHTML, and elements that are overwritten are GC'ed, - // even if there is a reference to them elsewhere - while ( cell.childNodes.length ) { - cell.removeChild( cell.firstChild ); - } - - cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' ); - }; - - // Are we reading last data from DOM or the data object? - if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) { - // Read the data from the DOM - row._aData = _fnGetRowElements( - settings, row, colIdx, colIdx === undefined ? undefined : row._aData - ) - .data; - } - else { - // Reading from data object, update the DOM - var cells = row.anCells; - - if ( cells ) { - if ( colIdx !== undefined ) { - cellWrite( cells[colIdx], colIdx ); - } - else { - for ( i=0, ien=cells.length ; i ').appendTo( thead ); - } - - for ( i=0, ien=columns.length ; i tr').attr('role', 'row'); - - /* Deal with the footer - add classes if required */ - $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH ); - $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH ); - - // Cache the footer cells. Note that we only take the cells from the first - // row in the footer. If there is more than one row the user wants to - // interact with, they need to use the table().foot() method. Note also this - // allows cells to be used for multiple columns using colspan - if ( tfoot !== null ) { - var cells = oSettings.aoFooter[0]; - - for ( i=0, ien=cells.length ; i =0 ; j-- ) - { - if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden ) - { - aoLocal[i].splice( j, 1 ); - } - } - - /* Prep the applied array - it needs an element for each row */ - aApplied.push( [] ); - } - - for ( i=0, iLen=aoLocal.length ; i = oSettings.fnRecordsDisplay() ? - 0 : - iInitDisplayStart; - - oSettings.iInitDisplayStart = -1; - } - - var iDisplayStart = oSettings._iDisplayStart; - var iDisplayEnd = oSettings.fnDisplayEnd(); - - /* Server-side processing draw intercept */ - if ( oSettings.bDeferLoading ) - { - oSettings.bDeferLoading = false; - oSettings.iDraw++; - _fnProcessingDisplay( oSettings, false ); - } - else if ( !bServerSide ) - { - oSettings.iDraw++; - } - else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) ) - { - return; - } - - if ( aiDisplay.length !== 0 ) - { - var iStart = bServerSide ? 0 : iDisplayStart; - var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd; - - for ( var j=iStart ; j ', { 'class': iStripes ? asStripeClasses[0] : '' } ) - .append( $(' ', { - 'valign': 'top', - 'colSpan': _fnVisbleColumns( oSettings ), - 'class': oSettings.oClasses.sRowEmpty - } ).html( sZero ) )[0]; - } - - /* Header and footer callbacks */ - _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], - _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); - - _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], - _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); - - var body = $(oSettings.nTBody); - - body.children().detach(); - body.append( $(anRows) ); - - /* Call all required callback functions for the end of a draw */ - _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); - - /* Draw is complete, sorting and filtering must be as well */ - oSettings.bSorted = false; - oSettings.bFiltered = false; - oSettings.bDrawing = false; - } - - - /** - * Redraw the table - taking account of the various features which are enabled - * @param {object} oSettings dataTables settings object - * @param {boolean} [holdPosition] Keep the current paging position. By default - * the paging is reset to the first page - * @memberof DataTable#oApi - */ - function _fnReDraw( settings, holdPosition ) - { - var - features = settings.oFeatures, - sort = features.bSort, - filter = features.bFilter; - - if ( sort ) { - _fnSort( settings ); - } - - if ( filter ) { - _fnFilterComplete( settings, settings.oPreviousSearch ); - } - else { - // No filtering, so we want to just use the display master - settings.aiDisplay = settings.aiDisplayMaster.slice(); - } - - if ( holdPosition !== true ) { - settings._iDisplayStart = 0; - } - - // Let any modules know about the draw hold position state (used by - // scrolling internally) - settings._drawHold = holdPosition; - - _fnDraw( settings ); - - settings._drawHold = false; - } - - - /** - * Add the options to the page HTML for the table - * @param {object} oSettings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnAddOptionsHtml ( oSettings ) - { - var classes = oSettings.oClasses; - var table = $(oSettings.nTable); - var holding = $('').insertBefore( table ); // Holding element for speed - var features = oSettings.oFeatures; - - // All DataTables are wrapped in a div - var insert = $('', { - id: oSettings.sTableId+'_wrapper', - 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter) - } ); - - oSettings.nHolding = holding[0]; - oSettings.nTableWrapper = insert[0]; - oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; - - /* Loop over the user set positioning and place the elements as needed */ - var aDom = oSettings.sDom.split(''); - var featureNode, cOption, nNewNode, cNext, sAttr, j; - for ( var i=0 ; i ')[0]; - - /* Check to see if we should append an id and/or a class name to the container */ - cNext = aDom[i+1]; - if ( cNext == "'" || cNext == '"' ) - { - sAttr = ""; - j = 2; - while ( aDom[i+j] != cNext ) - { - sAttr += aDom[i+j]; - j++; - } - - /* Replace jQuery UI constants @todo depreciated */ - if ( sAttr == "H" ) - { - sAttr = classes.sJUIHeader; - } - else if ( sAttr == "F" ) - { - sAttr = classes.sJUIFooter; - } - - /* The attribute can be in the format of "#id.class", "#id" or "class" This logic - * breaks the string into parts and applies them as needed - */ - if ( sAttr.indexOf('.') != -1 ) - { - var aSplit = sAttr.split('.'); - nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); - nNewNode.className = aSplit[1]; - } - else if ( sAttr.charAt(0) == "#" ) - { - nNewNode.id = sAttr.substr(1, sAttr.length-1); - } - else - { - nNewNode.className = sAttr; - } - - i += j; /* Move along the position array */ - } - - insert.append( nNewNode ); - insert = $(nNewNode); - } - else if ( cOption == '>' ) - { - /* End container div */ - insert = insert.parent(); - } - // @todo Move options into their own plugins? - else if ( cOption == 'l' && features.bPaginate && features.bLengthChange ) - { - /* Length */ - featureNode = _fnFeatureHtmlLength( oSettings ); - } - else if ( cOption == 'f' && features.bFilter ) - { - /* Filter */ - featureNode = _fnFeatureHtmlFilter( oSettings ); - } - else if ( cOption == 'r' && features.bProcessing ) - { - /* pRocessing */ - featureNode = _fnFeatureHtmlProcessing( oSettings ); - } - else if ( cOption == 't' ) - { - /* Table */ - featureNode = _fnFeatureHtmlTable( oSettings ); - } - else if ( cOption == 'i' && features.bInfo ) - { - /* Info */ - featureNode = _fnFeatureHtmlInfo( oSettings ); - } - else if ( cOption == 'p' && features.bPaginate ) - { - /* Pagination */ - featureNode = _fnFeatureHtmlPaginate( oSettings ); - } - else if ( DataTable.ext.feature.length !== 0 ) - { - /* Plug-in features */ - var aoFeatures = DataTable.ext.feature; - for ( var k=0, kLen=aoFeatures.length ; k '; - - var str = language.sSearch; - str = str.match(/_INPUT_/) ? - str.replace('_INPUT_', input) : - str+input; - - var filter = $('', { - 'id': ! features.f ? tableId+'_filter' : null, - 'class': classes.sFilter - } ) - .append( $('' ).append( str ) ); - - var searchFn = function() { - /* Update all other filter input elements for the new display */ - var n = features.f; - var val = !this.value ? "" : this.value; // mental IE8 fix :-( - - /* Now do the filter */ - if ( val != previousSearch.sSearch ) { - _fnFilterComplete( settings, { - "sSearch": val, - "bRegex": previousSearch.bRegex, - "bSmart": previousSearch.bSmart , - "bCaseInsensitive": previousSearch.bCaseInsensitive - } ); - - // Need to redraw, without resorting - settings._iDisplayStart = 0; - _fnDraw( settings ); - } - }; - - var searchDelay = settings.searchDelay !== null ? - settings.searchDelay : - _fnDataSource( settings ) === 'ssp' ? - 400 : - 0; - - var jqFilter = $('input', filter) - .val( previousSearch.sSearch ) - .attr( 'placeholder', language.sSearchPlaceholder ) - .on( - 'keyup.DT search.DT input.DT paste.DT cut.DT', - searchDelay ? - _fnThrottle( searchFn, searchDelay ) : - searchFn - ) - .on( 'keypress.DT', function(e) { - /* Prevent form submission */ - if ( e.keyCode == 13 ) { - return false; - } - } ) - .attr('aria-controls', tableId); - - // Update the input elements whenever the table is filtered - $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) { - if ( settings === s ) { - // IE9 throws an 'unknown error' if document.activeElement is used - // inside an iframe or frame... - try { - if ( jqFilter[0] !== document.activeElement ) { - jqFilter.val( previousSearch.sSearch ); - } - } - catch ( e ) {} - } - } ); - - return filter[0]; - } - - - /** - * Filter the table using both the global filter and column based filtering - * @param {object} oSettings dataTables settings object - * @param {object} oSearch search information - * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0) - * @memberof DataTable#oApi - */ - function _fnFilterComplete ( oSettings, oInput, iForce ) - { - var oPrevSearch = oSettings.oPreviousSearch; - var aoPrevSearch = oSettings.aoPreSearchCols; - var fnSaveFilter = function ( oFilter ) { - /* Save the filtering values */ - oPrevSearch.sSearch = oFilter.sSearch; - oPrevSearch.bRegex = oFilter.bRegex; - oPrevSearch.bSmart = oFilter.bSmart; - oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive; - }; - var fnRegex = function ( o ) { - // Backwards compatibility with the bEscapeRegex option - return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex; - }; - - // Resolve any column types that are unknown due to addition or invalidation - // @todo As per sort - can this be moved into an event handler? - _fnColumnTypes( oSettings ); - - /* In server-side processing all filtering is done by the server, so no point hanging around here */ - if ( _fnDataSource( oSettings ) != 'ssp' ) - { - /* Global filter */ - _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive ); - fnSaveFilter( oInput ); - - /* Now do the individual column filter */ - for ( var i=0 ; i input.length || - input.indexOf(prevSearch) !== 0 || - settings.bSorted // On resort, the display master needs to be - // re-filtered since indexes will have changed - ) { - settings.aiDisplay = displayMaster.slice(); - } - - // Search the display array - display = settings.aiDisplay; - - for ( i=0 ; i ')[0]; - var __filter_div_textContent = __filter_div.textContent !== undefined; - - // Update the filtering data for each row if needed (by invalidation or first run) - function _fnFilterData ( settings ) - { - var columns = settings.aoColumns; - var column; - var i, j, ien, jen, filterData, cellData, row; - var fomatters = DataTable.ext.type.search; - var wasInvalidated = false; - - for ( i=0, ien=settings.aoData.length ; i ', { - 'class': settings.oClasses.sInfo, - 'id': ! nodes ? tid+'_info' : null - } ); - - if ( ! nodes ) { - // Update display on each draw - settings.aoDrawCallback.push( { - "fn": _fnUpdateInfo, - "sName": "information" - } ); - - n - .attr( 'role', 'status' ) - .attr( 'aria-live', 'polite' ); - - // Table is described by our info div - $(settings.nTable).attr( 'aria-describedby', tid+'_info' ); - } - - return n[0]; - } - - - /** - * Update the information elements in the display - * @param {object} settings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnUpdateInfo ( settings ) - { - /* Show information about the table */ - var nodes = settings.aanFeatures.i; - if ( nodes.length === 0 ) { - return; - } - - var - lang = settings.oLanguage, - start = settings._iDisplayStart+1, - end = settings.fnDisplayEnd(), - max = settings.fnRecordsTotal(), - total = settings.fnRecordsDisplay(), - out = total ? - lang.sInfo : - lang.sInfoEmpty; - - if ( total !== max ) { - /* Record set after filtering */ - out += ' ' + lang.sInfoFiltered; - } - - // Convert the macros - out += lang.sInfoPostFix; - out = _fnInfoMacros( settings, out ); - - var callback = lang.fnInfoCallback; - if ( callback !== null ) { - out = callback.call( settings.oInstance, - settings, start, end, max, total, out - ); - } - - $(nodes).html( out ); - } - - - function _fnInfoMacros ( settings, str ) - { - // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only - // internally - var - formatter = settings.fnFormatNumber, - start = settings._iDisplayStart+1, - len = settings._iDisplayLength, - vis = settings.fnRecordsDisplay(), - all = len === -1; - - return str. - replace(/_START_/g, formatter.call( settings, start ) ). - replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ). - replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ). - replace(/_TOTAL_/g, formatter.call( settings, vis ) ). - replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ). - replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ); - } - - - - /** - * Draw the table for the first time, adding all required features - * @param {object} settings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnInitialise ( settings ) - { - var i, iLen, iAjaxStart=settings.iInitDisplayStart; - var columns = settings.aoColumns, column; - var features = settings.oFeatures; - var deferLoading = settings.bDeferLoading; // value modified by the draw - - /* Ensure that the table data is fully initialised */ - if ( ! settings.bInitialised ) { - setTimeout( function(){ _fnInitialise( settings ); }, 200 ); - return; - } - - /* Show the display HTML options */ - _fnAddOptionsHtml( settings ); - - /* Build and draw the header / footer for the table */ - _fnBuildHead( settings ); - _fnDrawHead( settings, settings.aoHeader ); - _fnDrawHead( settings, settings.aoFooter ); - - /* Okay to show that something is going on now */ - _fnProcessingDisplay( settings, true ); - - /* Calculate sizes for columns */ - if ( features.bAutoWidth ) { - _fnCalculateColumnWidths( settings ); - } - - for ( i=0, iLen=columns.length ; i ', { - 'name': tableId+'_length', - 'aria-controls': tableId, - 'class': classes.sLengthSelect - } ); - - for ( var i=0, ien=lengths.length ; i ').addClass( classes.sLength ); - if ( ! settings.aanFeatures.l ) { - div[0].id = tableId+'_length'; - } - - div.children().append( - settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML ) - ); - - // Can't use `select` variable as user might provide their own and the - // reference is broken by the use of outerHTML - $('select', div) - .val( settings._iDisplayLength ) - .on( 'change.DT', function(e) { - _fnLengthChange( settings, $(this).val() ); - _fnDraw( settings ); - } ); - - // Update node value whenever anything changes the table's length - $(settings.nTable).on( 'length.dt.DT', function (e, s, len) { - if ( settings === s ) { - $('select', div).val( len ); - } - } ); - - return div[0]; - } - - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Note that most of the paging logic is done in - * DataTable.ext.pager - */ - - /** - * Generate the node required for default pagination - * @param {object} oSettings dataTables settings object - * @returns {node} Pagination feature node - * @memberof DataTable#oApi - */ - function _fnFeatureHtmlPaginate ( settings ) - { - var - type = settings.sPaginationType, - plugin = DataTable.ext.pager[ type ], - modern = typeof plugin === 'function', - redraw = function( settings ) { - _fnDraw( settings ); - }, - node = $('').addClass( settings.oClasses.sPaging + type )[0], - features = settings.aanFeatures; - - if ( ! modern ) { - plugin.fnInit( settings, node, redraw ); - } - - /* Add a draw callback for the pagination on first instance, to update the paging display */ - if ( ! features.p ) - { - node.id = settings.sTableId+'_paginate'; - - settings.aoDrawCallback.push( { - "fn": function( settings ) { - if ( modern ) { - var - start = settings._iDisplayStart, - len = settings._iDisplayLength, - visRecords = settings.fnRecordsDisplay(), - all = len === -1, - page = all ? 0 : Math.ceil( start / len ), - pages = all ? 1 : Math.ceil( visRecords / len ), - buttons = plugin(page, pages), - i, ien; - - for ( i=0, ien=features.p.length ; i records ) - { - start = 0; - } - } - else if ( action == "first" ) - { - start = 0; - } - else if ( action == "previous" ) - { - start = len >= 0 ? - start - len : - 0; - - if ( start < 0 ) - { - start = 0; - } - } - else if ( action == "next" ) - { - if ( start + len < records ) - { - start += len; - } - } - else if ( action == "last" ) - { - start = Math.floor( (records-1) / len) * len; - } - else - { - _fnLog( settings, 0, "Unknown paging action: "+action, 5 ); - } - - var changed = settings._iDisplayStart !== start; - settings._iDisplayStart = start; - - if ( changed ) { - _fnCallbackFire( settings, null, 'page', [settings] ); - - if ( redraw ) { - _fnDraw( settings ); - } - } - - return changed; - } - - - - /** - * Generate the node required for the processing node - * @param {object} settings dataTables settings object - * @returns {node} Processing element - * @memberof DataTable#oApi - */ - function _fnFeatureHtmlProcessing ( settings ) - { - return $('', { - 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null, - 'class': settings.oClasses.sProcessing - } ) - .html( settings.oLanguage.sProcessing ) - .insertBefore( settings.nTable )[0]; - } - - - /** - * Display or hide the processing indicator - * @param {object} settings dataTables settings object - * @param {bool} show Show the processing indicator (true) or not (false) - * @memberof DataTable#oApi - */ - function _fnProcessingDisplay ( settings, show ) - { - if ( settings.oFeatures.bProcessing ) { - $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' ); - } - - _fnCallbackFire( settings, null, 'processing', [settings, show] ); - } - - /** - * Add any control elements for the table - specifically scrolling - * @param {object} settings dataTables settings object - * @returns {node} Node to add to the DOM - * @memberof DataTable#oApi - */ - function _fnFeatureHtmlTable ( settings ) - { - var table = $(settings.nTable); - - // Add the ARIA grid role to the table - table.attr( 'role', 'grid' ); - - // Scrolling from here on in - var scroll = settings.oScroll; - - if ( scroll.sX === '' && scroll.sY === '' ) { - return settings.nTable; - } - - var scrollX = scroll.sX; - var scrollY = scroll.sY; - var classes = settings.oClasses; - var caption = table.children('caption'); - var captionSide = caption.length ? caption[0]._captionSide : null; - var headerClone = $( table[0].cloneNode(false) ); - var footerClone = $( table[0].cloneNode(false) ); - var footer = table.children('tfoot'); - var _div = ''; - var size = function ( s ) { - return !s ? null : _fnStringToCss( s ); - }; - - if ( ! footer.length ) { - footer = null; - } - - /* - * The HTML structure that we want to generate in this function is: - * div - scroller - * div - scroll head - * div - scroll head inner - * table - scroll head table - * thead - thead - * div - scroll body - * table - table (master table) - * thead - thead clone for sizing - * tbody - tbody - * div - scroll foot - * div - scroll foot inner - * table - scroll foot table - * tfoot - tfoot - */ - var scroller = $( _div, { 'class': classes.sScrollWrapper } ) - .append( - $(_div, { 'class': classes.sScrollHead } ) - .css( { - overflow: 'hidden', - position: 'relative', - border: 0, - width: scrollX ? size(scrollX) : '100%' - } ) - .append( - $(_div, { 'class': classes.sScrollHeadInner } ) - .css( { - 'box-sizing': 'content-box', - width: scroll.sXInner || '100%' - } ) - .append( - headerClone - .removeAttr('id') - .css( 'margin-left', 0 ) - .append( captionSide === 'top' ? caption : null ) - .append( - table.children('thead') - ) - ) - ) - ) - .append( - $(_div, { 'class': classes.sScrollBody } ) - .css( { - position: 'relative', - overflow: 'auto', - width: size( scrollX ) - } ) - .append( table ) - ); - - if ( footer ) { - scroller.append( - $(_div, { 'class': classes.sScrollFoot } ) - .css( { - overflow: 'hidden', - border: 0, - width: scrollX ? size(scrollX) : '100%' - } ) - .append( - $(_div, { 'class': classes.sScrollFootInner } ) - .append( - footerClone - .removeAttr('id') - .css( 'margin-left', 0 ) - .append( captionSide === 'bottom' ? caption : null ) - .append( - table.children('tfoot') - ) - ) - ) - ); - } - - var children = scroller.children(); - var scrollHead = children[0]; - var scrollBody = children[1]; - var scrollFoot = footer ? children[2] : null; - - // When the body is scrolled, then we also want to scroll the headers - if ( scrollX ) { - $(scrollBody).on( 'scroll.DT', function (e) { - var scrollLeft = this.scrollLeft; - - scrollHead.scrollLeft = scrollLeft; - - if ( footer ) { - scrollFoot.scrollLeft = scrollLeft; - } - } ); - } - - $(scrollBody).css( - scrollY && scroll.bCollapse ? 'max-height' : 'height', - scrollY - ); - - settings.nScrollHead = scrollHead; - settings.nScrollBody = scrollBody; - settings.nScrollFoot = scrollFoot; - - // On redraw - align columns - settings.aoDrawCallback.push( { - "fn": _fnScrollDraw, - "sName": "scrolling" - } ); - - return scroller[0]; - } - - - - /** - * Update the header, footer and body tables for resizing - i.e. column - * alignment. - * - * Welcome to the most horrible function DataTables. The process that this - * function follows is basically: - * 1. Re-create the table inside the scrolling div - * 2. Take live measurements from the DOM - * 3. Apply the measurements to align the columns - * 4. Clean up - * - * @param {object} settings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnScrollDraw ( settings ) - { - // Given that this is such a monster function, a lot of variables are use - // to try and keep the minimised size as small as possible - var - scroll = settings.oScroll, - scrollX = scroll.sX, - scrollXInner = scroll.sXInner, - scrollY = scroll.sY, - barWidth = scroll.iBarWidth, - divHeader = $(settings.nScrollHead), - divHeaderStyle = divHeader[0].style, - divHeaderInner = divHeader.children('div'), - divHeaderInnerStyle = divHeaderInner[0].style, - divHeaderTable = divHeaderInner.children('table'), - divBodyEl = settings.nScrollBody, - divBody = $(divBodyEl), - divBodyStyle = divBodyEl.style, - divFooter = $(settings.nScrollFoot), - divFooterInner = divFooter.children('div'), - divFooterTable = divFooterInner.children('table'), - header = $(settings.nTHead), - table = $(settings.nTable), - tableEl = table[0], - tableStyle = tableEl.style, - footer = settings.nTFoot ? $(settings.nTFoot) : null, - browser = settings.oBrowser, - ie67 = browser.bScrollOversize, - dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ), - headerTrgEls, footerTrgEls, - headerSrcEls, footerSrcEls, - headerCopy, footerCopy, - headerWidths=[], footerWidths=[], - headerContent=[], footerContent=[], - idx, correction, sanityWidth, - zeroOut = function(nSizer) { - var style = nSizer.style; - style.paddingTop = "0"; - style.paddingBottom = "0"; - style.borderTopWidth = "0"; - style.borderBottomWidth = "0"; - style.height = 0; - }; - - // If the scrollbar visibility has changed from the last draw, we need to - // adjust the column sizes as the table width will have changed to account - // for the scrollbar - var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight; - - if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) { - settings.scrollBarVis = scrollBarVis; - _fnAdjustColumnSizing( settings ); - return; // adjust column sizing will call this function again - } - else { - settings.scrollBarVis = scrollBarVis; - } - - /* - * 1. Re-create the table inside the scrolling div - */ - - // Remove the old minimised thead and tfoot elements in the inner table - table.children('thead, tfoot').remove(); - - if ( footer ) { - footerCopy = footer.clone().prependTo( table ); - footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized - footerSrcEls = footerCopy.find('tr'); - } - - // Clone the current header and footer elements and then place it into the inner table - headerCopy = header.clone().prependTo( table ); - headerTrgEls = header.find('tr'); // original header is in its own table - headerSrcEls = headerCopy.find('tr'); - headerCopy.find('th, td').removeAttr('tabindex'); - - - /* - * 2. Take live measurements from the DOM - do not alter the DOM itself! - */ - - // Remove old sizing and apply the calculated column widths - // Get the unique column headers in the newly created (cloned) header. We want to apply the - // calculated sizes to this header - if ( ! scrollX ) - { - divBodyStyle.width = '100%'; - divHeader[0].style.width = '100%'; - } - - $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) { - idx = _fnVisibleToColumnIndex( settings, i ); - el.style.width = settings.aoColumns[idx].sWidth; - } ); - - if ( footer ) { - _fnApplyToChildren( function(n) { - n.style.width = ""; - }, footerSrcEls ); - } - - // Size the table as a whole - sanityWidth = table.outerWidth(); - if ( scrollX === "" ) { - // No x scrolling - tableStyle.width = "100%"; - - // IE7 will make the width of the table when 100% include the scrollbar - // - which is shouldn't. When there is a scrollbar we need to take this - // into account. - if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight || - divBody.css('overflow-y') == "scroll") - ) { - tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth); - } - - // Recalculate the sanity width - sanityWidth = table.outerWidth(); - } - else if ( scrollXInner !== "" ) { - // legacy x scroll inner has been given - use it - tableStyle.width = _fnStringToCss(scrollXInner); - - // Recalculate the sanity width - sanityWidth = table.outerWidth(); - } - - // Hidden header should have zero height, so remove padding and borders. Then - // set the width based on the real headers - - // Apply all styles in one pass - _fnApplyToChildren( zeroOut, headerSrcEls ); - - // Read all widths in next pass - _fnApplyToChildren( function(nSizer) { - headerContent.push( nSizer.innerHTML ); - headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); - }, headerSrcEls ); - - // Apply all widths in final pass - _fnApplyToChildren( function(nToSize, i) { - // Only apply widths to the DataTables detected header cells - this - // prevents complex headers from having contradictory sizes applied - if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) { - nToSize.style.width = headerWidths[i]; - } - }, headerTrgEls ); - - $(headerSrcEls).height(0); - - /* Same again with the footer if we have one */ - if ( footer ) - { - _fnApplyToChildren( zeroOut, footerSrcEls ); - - _fnApplyToChildren( function(nSizer) { - footerContent.push( nSizer.innerHTML ); - footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); - }, footerSrcEls ); - - _fnApplyToChildren( function(nToSize, i) { - nToSize.style.width = footerWidths[i]; - }, footerTrgEls ); - - $(footerSrcEls).height(0); - } - - - /* - * 3. Apply the measurements - */ - - // "Hide" the header and footer that we used for the sizing. We need to keep - // the content of the cell so that the width applied to the header and body - // both match, but we want to hide it completely. We want to also fix their - // width to what they currently are - _fnApplyToChildren( function(nSizer, i) { - nSizer.innerHTML = ''; - nSizer.style.width = headerWidths[i]; - }, headerSrcEls ); - - if ( footer ) - { - _fnApplyToChildren( function(nSizer, i) { - nSizer.innerHTML = ''; - nSizer.style.width = footerWidths[i]; - }, footerSrcEls ); - } - - // Sanity check that the table is of a sensible width. If not then we are going to get - // misalignment - try to prevent this by not allowing the table to shrink below its min width - if ( table.outerWidth() < sanityWidth ) - { - // The min width depends upon if we have a vertical scrollbar visible or not */ - correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight || - divBody.css('overflow-y') == "scroll")) ? - sanityWidth+barWidth : - sanityWidth; - - // IE6/7 are a law unto themselves... - if ( ie67 && (divBodyEl.scrollHeight > - divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll") - ) { - tableStyle.width = _fnStringToCss( correction-barWidth ); - } - - // And give the user a warning that we've stopped the table getting too small - if ( scrollX === "" || scrollXInner !== "" ) { - _fnLog( settings, 1, 'Possible column misalignment', 6 ); - } - } - else - { - correction = '100%'; - } - - // Apply to the container elements - divBodyStyle.width = _fnStringToCss( correction ); - divHeaderStyle.width = _fnStringToCss( correction ); - - if ( footer ) { - settings.nScrollFoot.style.width = _fnStringToCss( correction ); - } - - - /* - * 4. Clean up - */ - if ( ! scrollY ) { - /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting - * the scrollbar height from the visible display, rather than adding it on. We need to - * set the height in order to sort this. Don't want to do it in any other browsers. - */ - if ( ie67 ) { - divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth ); - } - } - - /* Finally set the width's of the header and footer tables */ - var iOuterWidth = table.outerWidth(); - divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth ); - divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth ); - - // Figure out if there are scrollbar present - if so then we need a the header and footer to - // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) - var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; - var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); - divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px"; - - if ( footer ) { - divFooterTable[0].style.width = _fnStringToCss( iOuterWidth ); - divFooterInner[0].style.width = _fnStringToCss( iOuterWidth ); - divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px"; - } - - // Correct DOM ordering for colgroup - comes before the thead - table.children('colgroup').insertBefore( table.children('thead') ); - - /* Adjust the position of the header in case we loose the y-scrollbar */ - divBody.scroll(); - - // If sorting or filtering has occurred, jump the scrolling back to the top - // only if we aren't holding the position - if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) { - divBodyEl.scrollTop = 0; - } - } - - - - /** - * Apply a given function to the display child nodes of an element array (typically - * TD children of TR rows - * @param {function} fn Method to apply to the objects - * @param array {nodes} an1 List of elements to look through for display children - * @param array {nodes} an2 Another list (identical structure to the first) - optional - * @memberof DataTable#oApi - */ - function _fnApplyToChildren( fn, an1, an2 ) - { - var index=0, i=0, iLen=an1.length; - var nNode1, nNode2; - - while ( i < iLen ) { - nNode1 = an1[i].firstChild; - nNode2 = an2 ? an2[i].firstChild : null; - - while ( nNode1 ) { - if ( nNode1.nodeType === 1 ) { - if ( an2 ) { - fn( nNode1, nNode2, index ); - } - else { - fn( nNode1, index ); - } - - index++; - } - - nNode1 = nNode1.nextSibling; - nNode2 = an2 ? nNode2.nextSibling : null; - } - - i++; - } - } - - - - var __re_html_remove = /<.*?>/g; - - - /** - * Calculate the width of columns for the table - * @param {object} oSettings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnCalculateColumnWidths ( oSettings ) - { - var - table = oSettings.nTable, - columns = oSettings.aoColumns, - scroll = oSettings.oScroll, - scrollY = scroll.sY, - scrollX = scroll.sX, - scrollXInner = scroll.sXInner, - columnCount = columns.length, - visibleColumns = _fnGetColumns( oSettings, 'bVisible' ), - headerCells = $('th', oSettings.nTHead), - tableWidthAttr = table.getAttribute('width'), // from DOM element - tableContainer = table.parentNode, - userInputs = false, - i, column, columnIdx, width, outerWidth, - browser = oSettings.oBrowser, - ie67 = browser.bScrollOversize; - - var styleWidth = table.style.width; - if ( styleWidth && styleWidth.indexOf('%') !== -1 ) { - tableWidthAttr = styleWidth; - } - - /* Convert any user input sizes into pixel sizes */ - for ( i=0 ; i ').appendTo( tmpTable.find('tbody') ); - - // Clone the table header and footer - we can't use the header / footer - // from the cloned table, since if scrolling is active, the table's - // real header and footer are contained in different table tags - tmpTable.find('thead, tfoot').remove(); - tmpTable - .append( $(oSettings.nTHead).clone() ) - .append( $(oSettings.nTFoot).clone() ); - - // Remove any assigned widths from the footer (from scrolling) - tmpTable.find('tfoot th, tfoot td').css('width', ''); - - // Apply custom sizing to the cloned header - headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] ); - - for ( i=0 ; i ').css( { - width: column.sWidthOrig, - margin: 0, - padding: 0, - border: 0, - height: 1 - } ) ); - } - } - - // Find the widest cell for each column and put it into the table - if ( oSettings.aoData.length ) { - for ( i=0 ; i ').css( scrollX || scrollY ? - { - position: 'absolute', - top: 0, - left: 0, - height: 1, - right: 0, - overflow: 'hidden' - } : - {} - ) - .append( tmpTable ) - .appendTo( tableContainer ); - - // When scrolling (X or Y) we want to set the width of the table as - // appropriate. However, when not scrolling leave the table width as it - // is. This results in slightly different, but I think correct behaviour - if ( scrollX && scrollXInner ) { - tmpTable.width( scrollXInner ); - } - else if ( scrollX ) { - tmpTable.css( 'width', 'auto' ); - tmpTable.removeAttr('width'); - - // If there is no width attribute or style, then allow the table to - // collapse - if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) { - tmpTable.width( tableContainer.clientWidth ); - } - } - else if ( scrollY ) { - tmpTable.width( tableContainer.clientWidth ); - } - else if ( tableWidthAttr ) { - tmpTable.width( tableWidthAttr ); - } - - // Get the width of each column in the constructed table - we need to - // know the inner width (so it can be assigned to the other table's - // cells) and the outer width so we can calculate the full width of the - // table. This is safe since DataTables requires a unique cell for each - // column, but if ever a header can span multiple columns, this will - // need to be modified. - var total = 0; - for ( i=0 ; i ') - .css( 'width', _fnStringToCss( width ) ) - .appendTo( parent || document.body ); - - var val = n[0].offsetWidth; - n.remove(); - - return val; - } - - - /** - * Get the widest node - * @param {object} settings dataTables settings object - * @param {int} colIdx column of interest - * @returns {node} widest table node - * @memberof DataTable#oApi - */ - function _fnGetWidestNode( settings, colIdx ) - { - var idx = _fnGetMaxLenString( settings, colIdx ); - if ( idx < 0 ) { - return null; - } - - var data = settings.aoData[ idx ]; - return ! data.nTr ? // Might not have been created when deferred rendering - $(' ').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] : - data.anCells[ colIdx ]; - } - - - /** - * Get the maximum strlen for each data column - * @param {object} settings dataTables settings object - * @param {int} colIdx column of interest - * @returns {string} max string length for each column - * @memberof DataTable#oApi - */ - function _fnGetMaxLenString( settings, colIdx ) - { - var s, max=-1, maxIdx = -1; - - for ( var i=0, ien=settings.aoData.length ; i max ) { - max = s.length; - maxIdx = i; - } - } - - return maxIdx; - } - - - /** - * Append a CSS unit (only if required) to a string - * @param {string} value to css-ify - * @returns {string} value with css unit - * @memberof DataTable#oApi - */ - function _fnStringToCss( s ) - { - if ( s === null ) { - return '0px'; - } - - if ( typeof s == 'number' ) { - return s < 0 ? - '0px' : - s+'px'; - } - - // Check it has a unit character already - return s.match(/\d$/) ? - s+'px' : - s; - } - - - - function _fnSortFlatten ( settings ) - { - var - i, iLen, k, kLen, - aSort = [], - aiOrig = [], - aoColumns = settings.aoColumns, - aDataSort, iCol, sType, srcCol, - fixed = settings.aaSortingFixed, - fixedObj = $.isPlainObject( fixed ), - nestedSort = [], - add = function ( a ) { - if ( a.length && ! $.isArray( a[0] ) ) { - // 1D array - nestedSort.push( a ); - } - else { - // 2D array - $.merge( nestedSort, a ); - } - }; - - // Build the sort array, with pre-fix and post-fix options if they have been - // specified - if ( $.isArray( fixed ) ) { - add( fixed ); - } - - if ( fixedObj && fixed.pre ) { - add( fixed.pre ); - } - - add( settings.aaSorting ); - - if (fixedObj && fixed.post ) { - add( fixed.post ); - } - - for ( i=0 ; i y ? 1 : 0; - if ( test !== 0 ) { - return sort.dir === 'asc' ? test : -test; - } - } - - x = aiOrig[a]; - y = aiOrig[b]; - return x y ? 1 : 0; - } ); - } - else { - // Depreciated - remove in 1.11 (providing a plug-in option) - // Not all sort types have formatting methods, so we have to call their sorting - // methods. - displayMaster.sort( function ( a, b ) { - var - x, y, k, l, test, sort, fn, - len=aSort.length, - dataA = aoData[a]._aSortData, - dataB = aoData[b]._aSortData; - - for ( k=0 ; k y ? 1 : 0; - } ); - } - } - - /* Tell the draw function that we have sorted the data */ - oSettings.bSorted = true; - } - - - function _fnSortAria ( settings ) - { - var label; - var nextSort; - var columns = settings.aoColumns; - var aSort = _fnSortFlatten( settings ); - var oAria = settings.oLanguage.oAria; - - // ARIA attributes - need to loop all columns, to update all (removing old - // attributes as needed) - for ( var i=0, iLen=columns.length ; i /g, "" ); - var th = col.nTh; - - // IE7 is throwing an error when setting these properties with jQuery's - // attr() and removeAttr() methods... - th.removeAttribute('aria-sort'); - - /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ - if ( col.bSortable ) { - if ( aSort.length > 0 && aSort[0].col == i ) { - th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" ); - nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0]; - } - else { - nextSort = asSorting[0]; - } - - label = sTitle + ( nextSort === "asc" ? - oAria.sSortAscending : - oAria.sSortDescending - ); - } - else { - label = sTitle; - } - - th.setAttribute('aria-label', label); - } - } - - - /** - * Function to run on user sort request - * @param {object} settings dataTables settings object - * @param {node} attachTo node to attach the handler to - * @param {int} colIdx column sorting index - * @param {boolean} [append=false] Append the requested sort to the existing - * sort if true (i.e. multi-column sort) - * @param {function} [callback] callback function - * @memberof DataTable#oApi - */ - function _fnSortListener ( settings, colIdx, append, callback ) - { - var col = settings.aoColumns[ colIdx ]; - var sorting = settings.aaSorting; - var asSorting = col.asSorting; - var nextSortIdx; - var next = function ( a, overflow ) { - var idx = a._idx; - if ( idx === undefined ) { - idx = $.inArray( a[1], asSorting ); - } - - return idx+1 < asSorting.length ? - idx+1 : - overflow ? - null : - 0; - }; - - // Convert to 2D array if needed - if ( typeof sorting[0] === 'number' ) { - sorting = settings.aaSorting = [ sorting ]; - } - - // If appending the sort then we are multi-column sorting - if ( append && settings.oFeatures.bSortMulti ) { - // Are we already doing some kind of sort on this column? - var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') ); - - if ( sortIdx !== -1 ) { - // Yes, modify the sort - nextSortIdx = next( sorting[sortIdx], true ); - - if ( nextSortIdx === null && sorting.length === 1 ) { - nextSortIdx = 0; // can't remove sorting completely - } - - if ( nextSortIdx === null ) { - sorting.splice( sortIdx, 1 ); - } - else { - sorting[sortIdx][1] = asSorting[ nextSortIdx ]; - sorting[sortIdx]._idx = nextSortIdx; - } - } - else { - // No sort on this column yet - sorting.push( [ colIdx, asSorting[0], 0 ] ); - sorting[sorting.length-1]._idx = 0; - } - } - else if ( sorting.length && sorting[0][0] == colIdx ) { - // Single column - already sorting on this column, modify the sort - nextSortIdx = next( sorting[0] ); - - sorting.length = 1; - sorting[0][1] = asSorting[ nextSortIdx ]; - sorting[0]._idx = nextSortIdx; - } - else { - // Single column - sort only on this column - sorting.length = 0; - sorting.push( [ colIdx, asSorting[0] ] ); - sorting[0]._idx = 0; - } - - // Run the sort by calling a full redraw - _fnReDraw( settings ); - - // callback used for async user interaction - if ( typeof callback == 'function' ) { - callback( settings ); - } - } - - - /** - * Attach a sort handler (click) to a node - * @param {object} settings dataTables settings object - * @param {node} attachTo node to attach the handler to - * @param {int} colIdx column sorting index - * @param {function} [callback] callback function - * @memberof DataTable#oApi - */ - function _fnSortAttachListener ( settings, attachTo, colIdx, callback ) - { - var col = settings.aoColumns[ colIdx ]; - - _fnBindAction( attachTo, {}, function (e) { - /* If the column is not sortable - don't to anything */ - if ( col.bSortable === false ) { - return; - } - - // If processing is enabled use a timeout to allow the processing - // display to be shown - otherwise to it synchronously - if ( settings.oFeatures.bProcessing ) { - _fnProcessingDisplay( settings, true ); - - setTimeout( function() { - _fnSortListener( settings, colIdx, e.shiftKey, callback ); - - // In server-side processing, the draw callback will remove the - // processing display - if ( _fnDataSource( settings ) !== 'ssp' ) { - _fnProcessingDisplay( settings, false ); - } - }, 0 ); - } - else { - _fnSortListener( settings, colIdx, e.shiftKey, callback ); - } - } ); - } - - - /** - * Set the sorting classes on table's body, Note: it is safe to call this function - * when bSort and bSortClasses are false - * @param {object} oSettings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnSortingClasses( settings ) - { - var oldSort = settings.aLastSort; - var sortClass = settings.oClasses.sSortColumn; - var sort = _fnSortFlatten( settings ); - var features = settings.oFeatures; - var i, ien, colIdx; - - if ( features.bSort && features.bSortClasses ) { - // Remove old sorting classes - for ( i=0, ien=oldSort.length ; i 0 && s.time < +new Date() - (duration*1000) ) { - callback(); - return; - } - - // Number of columns have changed - all bets are off, no restore of settings - if ( s.columns && columns.length !== s.columns.length ) { - callback(); - return; - } - - // Store the saved state so it might be accessed at any time - settings.oLoadedState = $.extend( true, {}, s ); - - // Restore key features - todo - for 1.11 this needs to be done by - // subscribed events - if ( s.start !== undefined ) { - settings._iDisplayStart = s.start; - settings.iInitDisplayStart = s.start; - } - if ( s.length !== undefined ) { - settings._iDisplayLength = s.length; - } - - // Order - if ( s.order !== undefined ) { - settings.aaSorting = []; - $.each( s.order, function ( i, col ) { - settings.aaSorting.push( col[0] >= columns.length ? - [ 0, col[1] ] : - col - ); - } ); - } - - // Search - if ( s.search !== undefined ) { - $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) ); - } - - // Columns - // - if ( s.columns ) { - for ( i=0, ien=s.columns.length ; i = end ) - { - start = end - len; - } - - // Keep the start record on the current page - start -= (start % len); - - if ( len === -1 || start < 0 ) - { - start = 0; - } - - settings._iDisplayStart = start; - } - - - function _fnRenderer( settings, type ) - { - var renderer = settings.renderer; - var host = DataTable.ext.renderer[type]; - - if ( $.isPlainObject( renderer ) && renderer[type] ) { - // Specific renderer for this type. If available use it, otherwise use - // the default. - return host[renderer[type]] || host._; - } - else if ( typeof renderer === 'string' ) { - // Common renderer - if there is one available for this type use it, - // otherwise use the default - return host[renderer] || host._; - } - - // Use the default - return host._; - } - - - /** - * Detect the data source being used for the table. Used to simplify the code - * a little (ajax) and to make it compress a little smaller. - * - * @param {object} settings dataTables settings object - * @returns {string} Data source - * @memberof DataTable#oApi - */ - function _fnDataSource ( settings ) - { - if ( settings.oFeatures.bServerSide ) { - return 'ssp'; - } - else if ( settings.ajax || settings.sAjaxSource ) { - return 'ajax'; - } - return 'dom'; - } - - - - - /** - * Computed structure of the DataTables API, defined by the options passed to - * `DataTable.Api.register()` when building the API. - * - * The structure is built in order to speed creation and extension of the Api - * objects since the extensions are effectively pre-parsed. - * - * The array is an array of objects with the following structure, where this - * base array represents the Api prototype base: - * - * [ - * { - * name: 'data' -- string - Property name - * val: function () {}, -- function - Api method (or undefined if just an object - * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result - * propExt: [ ... ] -- array - Array of Api object definitions to extend the property - * }, - * { - * name: 'row' - * val: {}, - * methodExt: [ ... ], - * propExt: [ - * { - * name: 'data' - * val: function () {}, - * methodExt: [ ... ], - * propExt: [ ... ] - * }, - * ... - * ] - * } - * ] - * - * @type {Array} - * @ignore - */ - var __apiStruct = []; - - - /** - * `Array.prototype` reference. - * - * @type object - * @ignore - */ - var __arrayProto = Array.prototype; - - - /** - * Abstraction for `context` parameter of the `Api` constructor to allow it to - * take several different forms for ease of use. - * - * Each of the input parameter types will be converted to a DataTables settings - * object where possible. - * - * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one - * of: - * - * * `string` - jQuery selector. Any DataTables' matching the given selector - * with be found and used. - * * `node` - `TABLE` node which has already been formed into a DataTable. - * * `jQuery` - A jQuery object of `TABLE` nodes. - * * `object` - DataTables settings object - * * `DataTables.Api` - API instance - * @return {array|null} Matching DataTables settings objects. `null` or - * `undefined` is returned if no matching DataTable is found. - * @ignore - */ - var _toSettings = function ( mixed ) - { - var idx, jq; - var settings = DataTable.settings; - var tables = $.map( settings, function (el, i) { - return el.nTable; - } ); - - if ( ! mixed ) { - return []; - } - else if ( mixed.nTable && mixed.oApi ) { - // DataTables settings object - return [ mixed ]; - } - else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) { - // Table node - idx = $.inArray( mixed, tables ); - return idx !== -1 ? [ settings[idx] ] : null; - } - else if ( mixed && typeof mixed.settings === 'function' ) { - return mixed.settings().toArray(); - } - else if ( typeof mixed === 'string' ) { - // jQuery selector - jq = $(mixed); - } - else if ( mixed instanceof $ ) { - // jQuery object (also DataTables instance) - jq = mixed; - } - - if ( jq ) { - return jq.map( function(i) { - idx = $.inArray( this, tables ); - return idx !== -1 ? settings[idx] : null; - } ).toArray(); - } - }; - - - /** - * DataTables API class - used to control and interface with one or more - * DataTables enhanced tables. - * - * The API class is heavily based on jQuery, presenting a chainable interface - * that you can use to interact with tables. Each instance of the API class has - * a "context" - i.e. the tables that it will operate on. This could be a single - * table, all tables on a page or a sub-set thereof. - * - * Additionally the API is designed to allow you to easily work with the data in - * the tables, retrieving and manipulating it as required. This is done by - * presenting the API class as an array like interface. The contents of the - * array depend upon the actions requested by each method (for example - * `rows().nodes()` will return an array of nodes, while `rows().data()` will - * return an array of objects or arrays depending upon your table's - * configuration). The API object has a number of array like methods (`push`, - * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`, - * `unique` etc) to assist your working with the data held in a table. - * - * Most methods (those which return an Api instance) are chainable, which means - * the return from a method call also has all of the methods available that the - * top level object had. For example, these two calls are equivalent: - * - * // Not chained - * api.row.add( {...} ); - * api.draw(); - * - * // Chained - * api.row.add( {...} ).draw(); - * - * @class DataTable.Api - * @param {array|object|string|jQuery} context DataTable identifier. This is - * used to define which DataTables enhanced tables this API will operate on. - * Can be one of: - * - * * `string` - jQuery selector. Any DataTables' matching the given selector - * with be found and used. - * * `node` - `TABLE` node which has already been formed into a DataTable. - * * `jQuery` - A jQuery object of `TABLE` nodes. - * * `object` - DataTables settings object - * @param {array} [data] Data to initialise the Api instance with. - * - * @example - * // Direct initialisation during DataTables construction - * var api = $('#example').DataTable(); - * - * @example - * // Initialisation using a DataTables jQuery object - * var api = $('#example').dataTable().api(); - * - * @example - * // Initialisation as a constructor - * var api = new $.fn.DataTable.Api( 'table.dataTable' ); - */ - _Api = function ( context, data ) - { - if ( ! (this instanceof _Api) ) { - return new _Api( context, data ); - } - - var settings = []; - var ctxSettings = function ( o ) { - var a = _toSettings( o ); - if ( a ) { - settings = settings.concat( a ); - } - }; - - if ( $.isArray( context ) ) { - for ( var i=0, ien=context.length ; i idx ? - new _Api( ctx[idx], this[idx] ) : - null; - }, - - - filter: function ( fn ) - { - var a = []; - - if ( __arrayProto.filter ) { - a = __arrayProto.filter.call( this, fn, this ); - } - else { - // Compatibility for browsers without EMCA-252-5 (JS 1.6) - for ( var i=0, ien=this.length ; i 0 ) { - return ctx[0].json; - } - - // else return undefined; - } ); - - - /** - * Get the data submitted in the last Ajax request - */ - _api_register( 'ajax.params()', function () { - var ctx = this.context; - - if ( ctx.length > 0 ) { - return ctx[0].oAjaxData; - } - - // else return undefined; - } ); - - - /** - * Reload tables from the Ajax data source. Note that this function will - * automatically re-draw the table when the remote data has been loaded. - * - * @param {boolean} [reset=true] Reset (default) or hold the current paging - * position. A full re-sort and re-filter is performed when this method is - * called, which is why the pagination reset is the default action. - * @returns {DataTables.Api} this - */ - _api_register( 'ajax.reload()', function ( callback, resetPaging ) { - return this.iterator( 'table', function (settings) { - __reload( settings, resetPaging===false, callback ); - } ); - } ); - - - /** - * Get the current Ajax URL. Note that this returns the URL from the first - * table in the current context. - * - * @return {string} Current Ajax source URL - *//** - * Set the Ajax URL. Note that this will set the URL for all tables in the - * current context. - * - * @param {string} url URL to set. - * @returns {DataTables.Api} this - */ - _api_register( 'ajax.url()', function ( url ) { - var ctx = this.context; - - if ( url === undefined ) { - // get - if ( ctx.length === 0 ) { - return undefined; - } - ctx = ctx[0]; - - return ctx.ajax ? - $.isPlainObject( ctx.ajax ) ? - ctx.ajax.url : - ctx.ajax : - ctx.sAjaxSource; - } - - // set - return this.iterator( 'table', function ( settings ) { - if ( $.isPlainObject( settings.ajax ) ) { - settings.ajax.url = url; - } - else { - settings.ajax = url; - } - // No need to consider sAjaxSource here since DataTables gives priority - // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any - // value of `sAjaxSource` redundant. - } ); - } ); - - - /** - * Load data from the newly set Ajax URL. Note that this method is only - * available when `ajax.url()` is used to set a URL. Additionally, this method - * has the same effect as calling `ajax.reload()` but is provided for - * convenience when setting a new URL. Like `ajax.reload()` it will - * automatically redraw the table once the remote data has been loaded. - * - * @returns {DataTables.Api} this - */ - _api_register( 'ajax.url().load()', function ( callback, resetPaging ) { - // Same as a reload, but makes sense to present it for easy access after a - // url change - return this.iterator( 'table', function ( ctx ) { - __reload( ctx, resetPaging===false, callback ); - } ); - } ); - - - - - var _selector_run = function ( type, selector, selectFn, settings, opts ) - { - var - out = [], res, - a, i, ien, j, jen, - selectorType = typeof selector; - - // Can't just check for isArray here, as an API or jQuery instance might be - // given with their array like look - if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) { - selector = [ selector ]; - } - - for ( i=0, ien=selector.length ; i 0 ) { - // Assign the first element to the first item in the instance - // and truncate the instance and context - inst[0] = inst[i]; - inst[0].length = 1; - inst.length = 1; - inst.context = [ inst.context[i] ]; - - return inst; - } - } - - // Not found - return an empty instance - inst.length = 0; - return inst; - }; - - - var _selector_row_indexes = function ( settings, opts ) - { - var - i, ien, tmp, a=[], - displayFiltered = settings.aiDisplay, - displayMaster = settings.aiDisplayMaster; - - var - search = opts.search, // none, applied, removed - order = opts.order, // applied, current, index (original - compatibility with 1.9) - page = opts.page; // all, current - - if ( _fnDataSource( settings ) == 'ssp' ) { - // In server-side processing mode, most options are irrelevant since - // rows not shown don't exist and the index order is the applied order - // Removed is a special case - for consistency just return an empty - // array - return search === 'removed' ? - [] : - _range( 0, displayMaster.length ); - } - else if ( page == 'current' ) { - // Current page implies that order=current and fitler=applied, since it is - // fairly senseless otherwise, regardless of what order and search actually - // are - for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i = 0 && search == 'applied') ) - { - a.push( i ); - } - } - } - } - - return a; - }; - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Rows - * - * {} - no selector - use all available rows - * {integer} - row aoData index - * {node} - TR node - * {string} - jQuery selector to apply to the TR elements - * {array} - jQuery array of nodes, or simply an array of TR nodes - * - */ - - - var __row_selector = function ( settings, selector, opts ) - { - var rows; - var run = function ( sel ) { - var selInt = _intVal( sel ); - var i, ien; - - // Short cut - selector is a number and no options provided (default is - // all records, so no need to check if the index is in there, since it - // must be - dev error if the index doesn't exist). - if ( selInt !== null && ! opts ) { - return [ selInt ]; - } - - if ( ! rows ) { - rows = _selector_row_indexes( settings, opts ); - } - - if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) { - // Selector - integer - return [ selInt ]; - } - else if ( sel === null || sel === undefined || sel === '' ) { - // Selector - none - return rows; - } - - // Selector - function - if ( typeof sel === 'function' ) { - return $.map( rows, function (idx) { - var row = settings.aoData[ idx ]; - return sel( idx, row._aData, row.nTr ) ? idx : null; - } ); - } - - // Get nodes in the order from the `rows` array with null values removed - var nodes = _removeEmpty( - _pluck_order( settings.aoData, rows, 'nTr' ) - ); - - // Selector - node - if ( sel.nodeName ) { - if ( sel._DT_RowIndex !== undefined ) { - return [ sel._DT_RowIndex ]; // Property added by DT for fast lookup - } - else if ( sel._DT_CellIndex ) { - return [ sel._DT_CellIndex.row ]; - } - else { - var host = $(sel).closest('*[data-dt-row]'); - return host.length ? - [ host.data('dt-row') ] : - []; - } - } - - // ID selector. Want to always be able to select rows by id, regardless - // of if the tr element has been created or not, so can't rely upon - // jQuery here - hence a custom implementation. This does not match - // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything, - // but to select it using a CSS selector engine (like Sizzle or - // querySelect) it would need to need to be escaped for some characters. - // DataTables simplifies this for row selectors since you can select - // only a row. A # indicates an id any anything that follows is the id - - // unescaped. - if ( typeof sel === 'string' && sel.charAt(0) === '#' ) { - // get row index from id - var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ]; - if ( rowObj !== undefined ) { - return [ rowObj.idx ]; - } - - // need to fall through to jQuery in case there is DOM id that - // matches - } - - // Selector - jQuery selector string, array of nodes or jQuery object/ - // As jQuery's .filter() allows jQuery objects to be passed in filter, - // it also allows arrays, so this will cope with all three options - return $(nodes) - .filter( sel ) - .map( function () { - return this._DT_RowIndex; - } ) - .toArray(); - }; - - return _selector_run( 'row', selector, run, settings, opts ); - }; - - - _api_register( 'rows()', function ( selector, opts ) { - // argument shifting - if ( selector === undefined ) { - selector = ''; - } - else if ( $.isPlainObject( selector ) ) { - opts = selector; - selector = ''; - } - - opts = _selector_opts( opts ); - - var inst = this.iterator( 'table', function ( settings ) { - return __row_selector( settings, selector, opts ); - }, 1 ); - - // Want argument shifting here and in __row_selector? - inst.selector.rows = selector; - inst.selector.opts = opts; - - return inst; - } ); - - _api_register( 'rows().nodes()', function () { - return this.iterator( 'row', function ( settings, row ) { - return settings.aoData[ row ].nTr || undefined; - }, 1 ); - } ); - - _api_register( 'rows().data()', function () { - return this.iterator( true, 'rows', function ( settings, rows ) { - return _pluck_order( settings.aoData, rows, '_aData' ); - }, 1 ); - } ); - - _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) { - return this.iterator( 'row', function ( settings, row ) { - var r = settings.aoData[ row ]; - return type === 'search' ? r._aFilterData : r._aSortData; - }, 1 ); - } ); - - _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) { - return this.iterator( 'row', function ( settings, row ) { - _fnInvalidate( settings, row, src ); - } ); - } ); - - _api_registerPlural( 'rows().indexes()', 'row().index()', function () { - return this.iterator( 'row', function ( settings, row ) { - return row; - }, 1 ); - } ); - - _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) { - var a = []; - var context = this.context; - - // `iterator` will drop undefined values, but in this case we want them - for ( var i=0, ien=context.length ; i 0 ) { - settings._iRecordsDisplay--; - } - - // Check for an 'overflow' they case for displaying the table - _fnLengthOverflow( settings ); - - // Remove the row's ID reference if there is one - var id = settings.rowIdFn( rowData._aData ); - if ( id !== undefined ) { - delete settings.aIds[ id ]; - } - } ); - - this.iterator( 'table', function ( settings ) { - for ( var i=0, ien=settings.aoData.length ; i ').addClass( k ); - $('td', created) - .addClass( k ) - .html( r ) - [0].colSpan = _fnVisbleColumns( ctx ); - - rows.push( created[0] ); - } - }; - - addRow( data, klass ); - - if ( row._details ) { - row._details.detach(); - } - - row._details = $(rows); - - // If the children were already shown, that state should be retained - if ( row._detailsShow ) { - row._details.insertAfter( row.nTr ); - } - }; - - - var __details_remove = function ( api, idx ) - { - var ctx = api.context; - - if ( ctx.length ) { - var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ]; - - if ( row && row._details ) { - row._details.remove(); - - row._detailsShow = undefined; - row._details = undefined; - } - } - }; - - - var __details_display = function ( api, show ) { - var ctx = api.context; - - if ( ctx.length && api.length ) { - var row = ctx[0].aoData[ api[0] ]; - - if ( row._details ) { - row._detailsShow = show; - - if ( show ) { - row._details.insertAfter( row.nTr ); - } - else { - row._details.detach(); - } - - __details_events( ctx[0] ); - } - } - }; - - - var __details_events = function ( settings ) - { - var api = new _Api( settings ); - var namespace = '.dt.DT_details'; - var drawEvent = 'draw'+namespace; - var colvisEvent = 'column-visibility'+namespace; - var destroyEvent = 'destroy'+namespace; - var data = settings.aoData; - - api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent ); - - if ( _pluck( data, '_details' ).length > 0 ) { - // On each draw, insert the required elements into the document - api.on( drawEvent, function ( e, ctx ) { - if ( settings !== ctx ) { - return; - } - - api.rows( {page:'current'} ).eq(0).each( function (idx) { - // Internal data grab - var row = data[ idx ]; - - if ( row._detailsShow ) { - row._details.insertAfter( row.nTr ); - } - } ); - } ); - - // Column visibility change - update the colspan - api.on( colvisEvent, function ( e, ctx, idx, vis ) { - if ( settings !== ctx ) { - return; - } - - // Update the colspan for the details rows (note, only if it already has - // a colspan) - var row, visible = _fnVisbleColumns( ctx ); - - for ( var i=0, ien=data.length ; i =0 count from left, <0 count from right) - * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right) - * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right) - * "{string}:name" - column name - * "{string}" - jQuery selector on column header nodes - * - */ - - // can be an array of these items, comma separated list, or an array of comma - // separated lists - - var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/; - - - // r1 and r2 are redundant - but it means that the parameters match for the - // iterator callback in columns().data() - var __columnData = function ( settings, column, r1, r2, rows ) { - var a = []; - for ( var row=0, ien=rows.length ; row = 0 ? - selInt : // Count from left - columns.length + selInt // Count from right (+ because its a negative value) - ]; - } - - // Selector = function - if ( typeof s === 'function' ) { - var rows = _selector_row_indexes( settings, opts ); - - return $.map( columns, function (col, idx) { - return s( - idx, - __columnData( settings, idx, 0, 0, rows ), - nodes[ idx ] - ) ? idx : null; - } ); - } - - // jQuery or string selector - var match = typeof s === 'string' ? - s.match( __re_column_selector ) : - ''; - - if ( match ) { - switch( match[2] ) { - case 'visIdx': - case 'visible': - var idx = parseInt( match[1], 10 ); - // Visible index given, convert to column index - if ( idx < 0 ) { - // Counting from the right - var visColumns = $.map( columns, function (col,i) { - return col.bVisible ? i : null; - } ); - return [ visColumns[ visColumns.length + idx ] ]; - } - // Counting from the left - return [ _fnVisibleToColumnIndex( settings, idx ) ]; - - case 'name': - // match by name. `names` is column index complete and in order - return $.map( names, function (name, i) { - return name === match[1] ? i : null; - } ); - - default: - return []; - } - } - - // Cell in the table body - if ( s.nodeName && s._DT_CellIndex ) { - return [ s._DT_CellIndex.column ]; - } - - // jQuery selector on the TH elements for the columns - var jqResult = $( nodes ) - .filter( s ) - .map( function () { - return $.inArray( this, nodes ); // `nodes` is column index complete and in order - } ) - .toArray(); - - if ( jqResult.length || ! s.nodeName ) { - return jqResult; - } - - // Otherwise a node which might have a `dt-column` data attribute, or be - // a child or such an element - var host = $(s).closest('*[data-dt-column]'); - return host.length ? - [ host.data('dt-column') ] : - []; - }; - - return _selector_run( 'column', selector, run, settings, opts ); - }; - - - var __setColumnVis = function ( settings, column, vis ) { - var - cols = settings.aoColumns, - col = cols[ column ], - data = settings.aoData, - row, cells, i, ien, tr; - - // Get - if ( vis === undefined ) { - return col.bVisible; - } - - // Set - // No change - if ( col.bVisible === vis ) { - return; - } - - if ( vis ) { - // Insert column - // Need to decide if we should use appendChild or insertBefore - var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 ); - - for ( i=0, ien=data.length ; i iThat; - } - - return true; - }; - - - /** - * Check if a `