Ad Inserter – WordPress Ads Management with AdSense Header Integration - Version 2.3.2

Version Description

  • Added AdSense code generator for ad sizes using CSS media queries
  • Fix for slow updates caused by changed user agent (credits Olivier Langlois)
  • Fix for client-side insertion of non-English characters before/after HTML element
Download this release

Release Info

Developer spacetime
Plugin Icon 128x128 Ad Inserter – WordPress Ads Management with AdSense Header Integration
Version 2.3.2
Comparing to
See all releases

Code changes from version 2.3.1 to 2.3.2

ad-inserter.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  /*
4
  Plugin Name: Ad Inserter
5
- Version: 2.3.1
6
  Description: Ad management plugin with advanced advertising options to automatically insert ad codes on your website
7
  Author: Igor Funa
8
  Author URI: http://igorfuna.com/
@@ -13,6 +13,11 @@ Plugin URI: http://adinserter.pro/documentation
13
 
14
  Change Log
15
 
 
 
 
 
 
16
  Ad Inserter 2.3.1 - 2018-01-25
17
  - Added support for server-side insertion before/after any HTML element
18
  - Few minor bug fixes
@@ -725,6 +730,15 @@ if (($ai_wp_data [AI_WP_DEBUGGING] & AI_DEBUG_PROCESSING) != 0) {
725
 
726
 
727
 
 
 
 
 
 
 
 
 
 
728
  function ai_wp_default_editor () {
729
  return 'tinymce';
730
  }
@@ -1012,7 +1026,7 @@ function ai_block_insertion_status ($block, $ai_last_check) {
1012
  case AI_CHECK_DEBUG_NO_INSERTION: $status .= "DEBUG NO INSERTION"; break;
1013
  case AI_CHECK_PARAGRAPH_TAGS: $status .= "PARAGRAPH TAGS"; break;
1014
  case AI_CHECK_PARAGRAPHS_WITH_TAGS: $status .= "PARAGRAPHS WITH TAGS"; break;
1015
- case AI_CHECK_PARAGRAPHS_AFTER_BLOCKQUOTE_FIGURE: $status .= "PARAGRAPHS AFTER BLOCKQUOTE / FIGURE"; break;
1016
  case AI_CHECK_PARAGRAPHS_AFTER_MIN_MAX_WORDS: $status .= "PARAGRAPHS AFTER MIN MAX WORDS"; break;
1017
  case AI_CHECK_PARAGRAPHS_AFTER_TEXT: $status .= "PARAGRAPHS AFTER TEXT"; break;
1018
  case AI_CHECK_PARAGRAPHS_AFTER_CLEARANCE: $status .= "PARAGRAPHS AFTER CLEARANCE"; break;
@@ -1580,6 +1594,9 @@ function ai_admin_enqueue_scripts ($hook_suffix) {
1580
 
1581
  wp_enqueue_style ('ai-image-picker', plugins_url ('css/image-picker.css', __FILE__), array (), AD_INSERTER_VERSION);
1582
  wp_add_inline_style ('ai-image-picker', '.thumbnail {border-radius: 6px;}');
 
 
 
1583
  wp_enqueue_style ('ai-admin-css', plugins_url ('css/ad-inserter.css', __FILE__), array (), AD_INSERTER_VERSION);
1584
 
1585
  wp_add_inline_style ('ai-admin-css', '.notice {margin: 5px 15px 15px 0;}');
@@ -1610,6 +1627,11 @@ function ai_admin_enqueue_scripts ($hook_suffix) {
1610
  'jquery-ui-datepicker',
1611
  'jquery-ui-dialog',
1612
  ), AD_INSERTER_VERSION, true);
 
 
 
 
 
1613
  }
1614
 
1615
  wp_enqueue_style ('ai-admin-css-gen', plugins_url ('css/ai-admin.css', __FILE__), array (), AD_INSERTER_VERSION);
2
 
3
  /*
4
  Plugin Name: Ad Inserter
5
+ Version: 2.3.2
6
  Description: Ad management plugin with advanced advertising options to automatically insert ad codes on your website
7
  Author: Igor Funa
8
  Author URI: http://igorfuna.com/
13
 
14
  Change Log
15
 
16
+ Ad Inserter 2.3.2 - 2018-02-01
17
+ - Added AdSense code generator for ad sizes using CSS media queries
18
+ - Fix for slow updates caused by changed user agent (Pro only, credits Olivier Langlois, https://juicingforyourmanhood.com/affiliate_tools.html)
19
+ - Fix for client-side insertion of non-English characters before/after HTML element
20
+
21
  Ad Inserter 2.3.1 - 2018-01-25
22
  - Added support for server-side insertion before/after any HTML element
23
  - Few minor bug fixes
730
 
731
 
732
 
733
+ //add_filter ('the_generator', 'ai_the_generator');
734
+
735
+ //function ai_the_generator ($generator) {
736
+ // return preg_replace ('/content="(.*?)"/', 'content="$1, '.AD_INSERTER_NAME.' '. AD_INSERTER_VERSION.'"', $generator);
737
+ //}
738
+
739
+
740
+
741
+
742
  function ai_wp_default_editor () {
743
  return 'tinymce';
744
  }
1026
  case AI_CHECK_DEBUG_NO_INSERTION: $status .= "DEBUG NO INSERTION"; break;
1027
  case AI_CHECK_PARAGRAPH_TAGS: $status .= "PARAGRAPH TAGS"; break;
1028
  case AI_CHECK_PARAGRAPHS_WITH_TAGS: $status .= "PARAGRAPHS WITH TAGS"; break;
1029
+ case AI_CHECK_PARAGRAPHS_AFTER_NO_COUNTING_INSIDE: $status .= "PARAGRAPHS AFTER NO COUNTING INSIDE"; break;
1030
  case AI_CHECK_PARAGRAPHS_AFTER_MIN_MAX_WORDS: $status .= "PARAGRAPHS AFTER MIN MAX WORDS"; break;
1031
  case AI_CHECK_PARAGRAPHS_AFTER_TEXT: $status .= "PARAGRAPHS AFTER TEXT"; break;
1032
  case AI_CHECK_PARAGRAPHS_AFTER_CLEARANCE: $status .= "PARAGRAPHS AFTER CLEARANCE"; break;
1594
 
1595
  wp_enqueue_style ('ai-image-picker', plugins_url ('css/image-picker.css', __FILE__), array (), AD_INSERTER_VERSION);
1596
  wp_add_inline_style ('ai-image-picker', '.thumbnail {border-radius: 6px;}');
1597
+
1598
+ wp_enqueue_style ('ai-combobox-css', plugins_url ('css/jquery.scombobox.min.css', __FILE__), array (), AD_INSERTER_VERSION);
1599
+
1600
  wp_enqueue_style ('ai-admin-css', plugins_url ('css/ad-inserter.css', __FILE__), array (), AD_INSERTER_VERSION);
1601
 
1602
  wp_add_inline_style ('ai-admin-css', '.notice {margin: 5px 15px 15px 0;}');
1627
  'jquery-ui-datepicker',
1628
  'jquery-ui-dialog',
1629
  ), AD_INSERTER_VERSION, true);
1630
+
1631
+ wp_enqueue_script ('ai-combobox', plugins_url ('includes/js/jquery.scombobox.min.js', __FILE__), array (
1632
+ 'jquery',
1633
+ ), AD_INSERTER_VERSION , true);
1634
+ wp_enqueue_script ('ai-missed', plugins_url ('includes/js/missed.js', __FILE__), array (), AD_INSERTER_VERSION , true);
1635
  }
1636
 
1637
  wp_enqueue_style ('ai-admin-css-gen', plugins_url ('css/ai-admin.css', __FILE__), array (), AD_INSERTER_VERSION);
class.php CHANGED
@@ -1690,7 +1690,7 @@ abstract class ai_CodeBlock extends ai_BaseCodeBlock {
1690
  }
1691
 
1692
  $serverside_insertion_code = "<script>
1693
- {$code_before} ai_insert ('$insertion', '$selector', atob ('[#AI_CODE#]'));{$code_after}
1694
  </script>\n";
1695
  }
1696
 
@@ -2159,7 +2159,7 @@ abstract class ai_CodeBlock extends ai_BaseCodeBlock {
2159
  $paragraph_positions = $filtered_paragraph_positions;
2160
  }
2161
 
2162
- $ai_last_check = AI_CHECK_PARAGRAPHS_AFTER_BLOCKQUOTE_FIGURE;
2163
  if (count ($paragraph_positions) == 0) return $content;
2164
  }
2165
 
@@ -2754,7 +2754,7 @@ abstract class ai_CodeBlock extends ai_BaseCodeBlock {
2754
  $paragraph_positions = $filtered_paragraph_positions;
2755
  }
2756
 
2757
- $ai_last_check = AI_CHECK_PARAGRAPHS_AFTER_BLOCKQUOTE_FIGURE;
2758
  if (count ($paragraph_positions) == 0) return $content;
2759
  }
2760
 
@@ -4177,20 +4177,35 @@ class ai_code_generator {
4177
  }
4178
  break;
4179
  case AI_CODE_ADSENSE:
4180
- if ($data ['adsense-width'] != '') $data ['adsense-width'] = ' width: '. $data ['adsense-width']. 'px;';
4181
- if ($data ['adsense-height'] != '') $data ['adsense-height'] = ' height: '.$data ['adsense-height'].'px;';
4182
 
4183
- switch ($data ['adsense-type']) {
 
4184
 
 
4185
  case AI_ADSENSE_STANDARD:
4186
 
4187
- switch ($data ['adsense-responsive']) {
4188
- case 0:
4189
 
4190
  // Normal
4191
- $code = '<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
4192
  <ins class="adsbygoogle"
4193
- style="display: inline-block;'.$data ['adsense-width'].$data ['adsense-height'].'"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4194
  data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
4195
  data-ad-slot="'.$data ['adsense-ad-slot-id'].'"></ins>
4196
  <script>
@@ -4198,10 +4213,10 @@ class ai_code_generator {
4198
  </script>';
4199
  break;
4200
 
4201
- case 1:
4202
 
4203
  // Responsive
4204
- $code = '<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
4205
  <ins class="adsbygoogle"
4206
  style="display: block;"
4207
  data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
@@ -4215,13 +4230,13 @@ class ai_code_generator {
4215
  break;
4216
 
4217
  case AI_ADSENSE_LINK:
4218
- switch ($data ['adsense-responsive']) {
4219
- case 0:
4220
 
4221
  // Normal
4222
- $code = '<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
4223
  <ins class="adsbygoogle"
4224
- style="display: inline-block;'.$data ['adsense-width'].$data ['adsense-height'].'"
4225
  data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
4226
  data-ad-slot="'.$data ['adsense-ad-slot-id'].'"
4227
  data-ad-format="link"></ins>
@@ -4230,10 +4245,25 @@ class ai_code_generator {
4230
  </script>';
4231
  break;
4232
 
4233
- case 1:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4234
 
4235
  // Responsive
4236
- $code = '<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
4237
  <ins class="adsbygoogle"
4238
  style="display: block;"
4239
  data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
@@ -4247,7 +4277,7 @@ class ai_code_generator {
4247
  break;
4248
 
4249
  case AI_ADSENSE_IN_ARTICLE:
4250
- $code = '<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
4251
  <ins class="adsbygoogle"
4252
  style="display: block; text-align: center;"
4253
  data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
@@ -4260,7 +4290,7 @@ class ai_code_generator {
4260
  break;
4261
 
4262
  case AI_ADSENSE_IN_FEED:
4263
- $code = '<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
4264
  <ins class="adsbygoogle"
4265
  style="display: block;"
4266
  data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
@@ -4274,7 +4304,7 @@ class ai_code_generator {
4274
  break;
4275
 
4276
  case AI_ADSENSE_MATCHED_CONTENT:
4277
- $code = '<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
4278
  <ins class="adsbygoogle"
4279
  style="display: block;"
4280
  data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
@@ -4285,7 +4315,7 @@ class ai_code_generator {
4285
  </script>';
4286
  break;
4287
  case AI_ADSENSE_AUTO:
4288
- $code = '<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
4289
  <script>
4290
  (adsbygoogle = window.adsbygoogle || []).push({
4291
  google_ad_client: "ca-'.$data ['adsense-publisher-id'].'",
@@ -4347,6 +4377,48 @@ class ai_code_generator {
4347
  return $code;
4348
  }
4349
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4350
  public function import ($code){
4351
 
4352
  $amp = AI_ADSENSE_AMP_DISABLED;
@@ -4395,11 +4467,12 @@ class ai_code_generator {
4395
  'adsense-publisher-id' => '',
4396
  'adsense-ad-slot-id' => '',
4397
  'adsense-type' => AI_ADSENSE_STANDARD,
4398
- 'adsense-responsive' => 0,
4399
  'adsense-width' => '',
4400
  'adsense-height' => '',
4401
  'adsense-layout' => '',
4402
  'adsense-layout-key' => '',
 
4403
  'adsense-amp' => $amp,
4404
  );
4405
 
@@ -4417,7 +4490,67 @@ class ai_code_generator {
4417
  $style_height = preg_match ("/height\s*:\s*(\d+)px/", $adsense_style, $height_match);
4418
  if ($style_height) $data ['adsense-height'] = $height_match [1];
4419
 
4420
- $adsense_responsive = !$style_width && !$style_height;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4421
 
4422
  // $adsense_ad_format = $adsense_code [0]->getAttribute ('data-ad-format');
4423
  $adsense_ad_format = $adsense_code->item (0)->getAttribute ('data-ad-format');
@@ -4425,14 +4558,12 @@ class ai_code_generator {
4425
  case '':
4426
  break;
4427
  case 'auto':
4428
- if ($adsense_responsive) $data ['adsense-responsive'] = 1;
4429
  break;
4430
  case 'autorelaxed':
4431
  $data ['adsense-type'] = AI_ADSENSE_MATCHED_CONTENT;
4432
  break;
4433
  case 'link':
4434
  $data ['adsense-type'] = AI_ADSENSE_LINK;
4435
- if ($adsense_responsive) $data ['adsense-responsive'] = 1;
4436
  break;
4437
  case 'fluid':
4438
  // $adsense_ad_layout = $adsense_code [0]->getAttribute ('data-ad-layout');
@@ -4466,7 +4597,7 @@ class ai_code_generator {
4466
  'adsense-publisher-id' => '',
4467
  'adsense-ad-slot-id' => '',
4468
  'adsense-type' => AI_ADSENSE_STANDARD,
4469
- 'adsense-responsive' => 0,
4470
  'adsense-width' => '',
4471
  'adsense-height' => '',
4472
  'adsense-layout' => '',
@@ -4474,6 +4605,9 @@ class ai_code_generator {
4474
  'adsense-amp' => $amp,
4475
  );
4476
 
 
 
 
4477
  if (preg_match ("/google_ad_client.+[\"\'](.+?)[\"\']/", $code, $match)) {
4478
  $data ['adsense-publisher-id'] = str_replace ('ca-', '', $match [1]);
4479
  }
1690
  }
1691
 
1692
  $serverside_insertion_code = "<script>
1693
+ {$code_before} ai_insert ('$insertion', '$selector', jQuery.base64Decode ('[#AI_CODE#]'));{$code_after}
1694
  </script>\n";
1695
  }
1696
 
2159
  $paragraph_positions = $filtered_paragraph_positions;
2160
  }
2161
 
2162
+ $ai_last_check = AI_CHECK_PARAGRAPHS_AFTER_NO_COUNTING_INSIDE;
2163
  if (count ($paragraph_positions) == 0) return $content;
2164
  }
2165
 
2754
  $paragraph_positions = $filtered_paragraph_positions;
2755
  }
2756
 
2757
+ $ai_last_check = AI_CHECK_PARAGRAPHS_AFTER_NO_COUNTING_INSIDE;
2758
  if (count ($paragraph_positions) == 0) return $content;
2759
  }
2760
 
4177
  }
4178
  break;
4179
  case AI_CODE_ADSENSE:
4180
+ $adsense_size = ($data ['adsense-width'] != '' ? ' width: '. $data ['adsense-width']. 'px;' : '') . ($data ['adsense-height'] != '' ? ' height: '.$data ['adsense-height'].'px;' : '');
 
4181
 
4182
+ $code = '<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>';
4183
+ if ($data ['adsense-comment']) $code .= "\n<!-- " . $data ['adsense-comment'] . " -->";
4184
 
4185
+ switch ($data ['adsense-type']) {
4186
  case AI_ADSENSE_STANDARD:
4187
 
4188
+ switch ($data ['adsense-size']) {
4189
+ case AI_ADSENSE_SIZE_FIXED:
4190
 
4191
  // Normal
4192
+ $code .= '
4193
  <ins class="adsbygoogle"
4194
+ style="display: inline-block;'.$adsense_size.'"
4195
+ data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
4196
+ data-ad-slot="'.$data ['adsense-ad-slot-id'].'"></ins>
4197
+ <script>
4198
+ (adsbygoogle = window.adsbygoogle || []).push({});
4199
+ </script>';
4200
+ break;
4201
+
4202
+ case AI_ADSENSE_SIZE_FIXED_BY_VIEWPORT:
4203
+
4204
+ $code = $this->adsense_size_styles ($data) . $code;
4205
+
4206
+ // Normal
4207
+ $code .= '
4208
+ <ins class="adsbygoogle ' . AI_ADSENSE_BLOCK_CLASS .$data ['block'].'"
4209
  data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
4210
  data-ad-slot="'.$data ['adsense-ad-slot-id'].'"></ins>
4211
  <script>
4213
  </script>';
4214
  break;
4215
 
4216
+ case AI_ADSENSE_SIZE_RESPONSIVE:
4217
 
4218
  // Responsive
4219
+ $code .= '
4220
  <ins class="adsbygoogle"
4221
  style="display: block;"
4222
  data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
4230
  break;
4231
 
4232
  case AI_ADSENSE_LINK:
4233
+ switch ($data ['adsense-size']) {
4234
+ case AI_ADSENSE_SIZE_FIXED:
4235
 
4236
  // Normal
4237
+ $code .= '
4238
  <ins class="adsbygoogle"
4239
+ style="display: inline-block;'.$adsense_size.'"
4240
  data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
4241
  data-ad-slot="'.$data ['adsense-ad-slot-id'].'"
4242
  data-ad-format="link"></ins>
4245
  </script>';
4246
  break;
4247
 
4248
+ case AI_ADSENSE_SIZE_FIXED_BY_VIEWPORT:
4249
+
4250
+ $code = $this->adsense_size_styles ($data) . $code;
4251
+
4252
+ // Normal
4253
+ $code .= '
4254
+ <ins class="adsbygoogle ' . AI_ADSENSE_BLOCK_CLASS .$data ['block'].'"
4255
+ data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
4256
+ data-ad-slot="'.$data ['adsense-ad-slot-id'].'"
4257
+ data-ad-format="link"></ins>
4258
+ <script>
4259
+ (adsbygoogle = window.adsbygoogle || []).push({});
4260
+ </script>';
4261
+ break;
4262
+
4263
+ case AI_ADSENSE_SIZE_RESPONSIVE:
4264
 
4265
  // Responsive
4266
+ $code .= '
4267
  <ins class="adsbygoogle"
4268
  style="display: block;"
4269
  data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
4277
  break;
4278
 
4279
  case AI_ADSENSE_IN_ARTICLE:
4280
+ $code .= '
4281
  <ins class="adsbygoogle"
4282
  style="display: block; text-align: center;"
4283
  data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
4290
  break;
4291
 
4292
  case AI_ADSENSE_IN_FEED:
4293
+ $code .= '
4294
  <ins class="adsbygoogle"
4295
  style="display: block;"
4296
  data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
4304
  break;
4305
 
4306
  case AI_ADSENSE_MATCHED_CONTENT:
4307
+ $code .= '
4308
  <ins class="adsbygoogle"
4309
  style="display: block;"
4310
  data-ad-client="ca-'.$data ['adsense-publisher-id'].'"
4315
  </script>';
4316
  break;
4317
  case AI_ADSENSE_AUTO:
4318
+ $code .= '
4319
  <script>
4320
  (adsbygoogle = window.adsbygoogle || []).push({
4321
  google_ad_client: "ca-'.$data ['adsense-publisher-id'].'",
4377
  return $code;
4378
  }
4379
 
4380
+ public function adsense_size_styles ($data){
4381
+ $code = '<style>
4382
+ ';
4383
+ $display_inline = false;
4384
+ for ($viewport = AD_INSERTER_VIEWPORTS; $viewport >= 1; $viewport --) {
4385
+ $viewport_name = get_viewport_name ($viewport);
4386
+ $viewport_width = get_viewport_width ($viewport);
4387
+
4388
+ $adsense_width = $data ['adsense-viewports'][$viewport - 1]['width'];
4389
+ $adsense_height = $data ['adsense-viewports'][$viewport - 1]['height'];
4390
+
4391
+ if ($viewport_name != '') {
4392
+ if ($adsense_width > 0 && $adsense_height > 0) {
4393
+ if (!$display_inline) {
4394
+ $size_style = 'display: inline-block; ';
4395
+ $display_inline = true;
4396
+ } else $size_style = '';
4397
+
4398
+ $size_style .= 'width: ' . $adsense_width . 'px; height: ' .$adsense_height . 'px;';
4399
+ } else {
4400
+ $size_style = 'display: none;';
4401
+ $display_inline = false;
4402
+ }
4403
+
4404
+ switch ($viewport_width) {
4405
+ case 0:
4406
+ $code .= '.' . AI_ADSENSE_BLOCK_CLASS . $data ['block']. ' {' . $size_style . '}';
4407
+ break;
4408
+ default:
4409
+ $code .= '@media (min-width: '.$viewport_width.'px) {.' . AI_ADSENSE_BLOCK_CLASS . $data ['block']. ' {' . $size_style . '}}';
4410
+ break;
4411
+ }
4412
+
4413
+ $code .= ' /* ' . $viewport_name . ($viewport_width == 0 ? ', default' : '') . ' */' . "\n";
4414
+ }
4415
+ }
4416
+ $code .= '</style>
4417
+ ';
4418
+ return $code;
4419
+ }
4420
+
4421
+
4422
  public function import ($code){
4423
 
4424
  $amp = AI_ADSENSE_AMP_DISABLED;
4467
  'adsense-publisher-id' => '',
4468
  'adsense-ad-slot-id' => '',
4469
  'adsense-type' => AI_ADSENSE_STANDARD,
4470
+ 'adsense-size' => AI_ADSENSE_SIZE_FIXED,
4471
  'adsense-width' => '',
4472
  'adsense-height' => '',
4473
  'adsense-layout' => '',
4474
  'adsense-layout-key' => '',
4475
+ 'adsense-comment' => '',
4476
  'adsense-amp' => $amp,
4477
  );
4478
 
4490
  $style_height = preg_match ("/height\s*:\s*(\d+)px/", $adsense_style, $height_match);
4491
  if ($style_height) $data ['adsense-height'] = $height_match [1];
4492
 
4493
+ $display = '';
4494
+ $style_display = preg_match ("/display\s*:\s*([a-z\-]+)/", $adsense_style, $display_match);
4495
+ if ($style_display) $display = $display_match [1];
4496
+
4497
+ $adsense_class = trim ($adsense_code->item (0)->getAttribute ('class'));
4498
+ $adsense_classes = explode (' ', $adsense_class);
4499
+
4500
+ $adsense_size = !$style_width && !$style_height && $display == 'block' ? AI_ADSENSE_SIZE_RESPONSIVE : AI_ADSENSE_SIZE_FIXED;
4501
+
4502
+ if (count ($adsense_classes) == 2 && !$style_width && !$style_height) {
4503
+ $adsense_size = AI_ADSENSE_SIZE_FIXED_BY_VIEWPORT;
4504
+
4505
+ $viewport_class = $adsense_classes [1];
4506
+
4507
+ $style = preg_match ("#<style>(.+?)</style>#s", $code, $style_match);
4508
+ $style_lines = explode ("\n", trim ($style_match [1]));
4509
+
4510
+ $sizes = array ();
4511
+ $viewport_widths = array ();
4512
+ for ($viewport = 1; $viewport <= AD_INSERTER_VIEWPORTS; $viewport ++) {
4513
+ $viewport_name = get_viewport_name ($viewport);
4514
+ $viewport_width = get_viewport_width ($viewport);
4515
+ if ($viewport_name != '') {
4516
+ $viewport_widths [] = $viewport_width;
4517
+ $sizes []= array (0 => '', 1 => '');
4518
+ }
4519
+ }
4520
+ $viewport_widths = array_reverse ($viewport_widths);
4521
+
4522
+ if (count ($style_lines) == count ($sizes)) {
4523
+ foreach ($style_lines as $index => $style_line) {
4524
+ if (strpos ($style_line, $viewport_class) !== false) {
4525
+
4526
+ $min_width = preg_match ("/min-width\s*:\s*(\d+)px/", $style_line, $min_width_match);
4527
+ $viewport_width = $min_width ? $min_width_match [1] : '';
4528
+
4529
+ if ($viewport_width == $viewport_widths [$index]) {
4530
+ $styles = explode ($viewport_class, $style_line);
4531
+ $style_line = $styles [1];
4532
+
4533
+ $style_width = preg_match ("/width\s*:\s*(\d+)px/", $style_line, $width_match);
4534
+ $adsense_width = $style_width ? $width_match [1] : '';
4535
+
4536
+ $style_height = preg_match ("/height\s*:\s*(\d+)px/", $style_line, $height_match);
4537
+ $adsense_height = $style_height ? $height_match [1] : '';
4538
+
4539
+ $sizes [$index] = array (0 => $adsense_width, 1 => $adsense_height);
4540
+ }
4541
+
4542
+ } else $sizes [$index] = array ('', '');
4543
+ }
4544
+ $sizes = array_reverse ($sizes);
4545
+ }
4546
+
4547
+ $data ['adsense-sizes'] = $sizes;
4548
+ }
4549
+
4550
+ $data ['adsense-size'] = $adsense_size;
4551
+
4552
+ $comment = preg_match ("#<!--(.+?)-->#", $code, $comment_match);
4553
+ if ($comment) $data ['adsense-comment'] = trim ($comment_match [1]);
4554
 
4555
  // $adsense_ad_format = $adsense_code [0]->getAttribute ('data-ad-format');
4556
  $adsense_ad_format = $adsense_code->item (0)->getAttribute ('data-ad-format');
4558
  case '':
4559
  break;
4560
  case 'auto':
 
4561
  break;
4562
  case 'autorelaxed':
4563
  $data ['adsense-type'] = AI_ADSENSE_MATCHED_CONTENT;
4564
  break;
4565
  case 'link':
4566
  $data ['adsense-type'] = AI_ADSENSE_LINK;
 
4567
  break;
4568
  case 'fluid':
4569
  // $adsense_ad_layout = $adsense_code [0]->getAttribute ('data-ad-layout');
4597
  'adsense-publisher-id' => '',
4598
  'adsense-ad-slot-id' => '',
4599
  'adsense-type' => AI_ADSENSE_STANDARD,
4600
+ 'adsense-size' => AI_ADSENSE_SIZE_FIXED,
4601
  'adsense-width' => '',
4602
  'adsense-height' => '',
4603
  'adsense-layout' => '',
4605
  'adsense-amp' => $amp,
4606
  );
4607
 
4608
+ $comment = preg_match ("#<!--(.+?)-->#", $code, $comment_match);
4609
+ if ($comment) $data ['adsense-comment'] = trim ($comment_match [1]);
4610
+
4611
  if (preg_match ("/google_ad_client.+[\"\'](.+?)[\"\']/", $code, $match)) {
4612
  $data ['adsense-publisher-id'] = str_replace ('ca-', '', $match [1]);
4613
  }
constants.php CHANGED
@@ -24,7 +24,7 @@ if (!defined( 'AD_INSERTER_NAME'))
24
  define ('AD_INSERTER_NAME', 'Ad Inserter');
25
 
26
  if (!defined( 'AD_INSERTER_VERSION'))
27
- define ('AD_INSERTER_VERSION', '2.3.1');
28
 
29
  if (!defined ('AD_INSERTER_PLUGIN_BASENAME'))
30
  define ('AD_INSERTER_PLUGIN_BASENAME', plugin_basename (__FILE__));
@@ -639,7 +639,7 @@ define ('AI_CHECK_PARAGRAPHS_MIN_NUMBER', 32);
639
  define ('AI_CHECK_DEBUG_NO_INSERTION', 33);
640
  define ('AI_CHECK_PARAGRAPH_TAGS', 34);
641
  define ('AI_CHECK_PARAGRAPHS_WITH_TAGS', 35);
642
- define ('AI_CHECK_PARAGRAPHS_AFTER_BLOCKQUOTE_FIGURE', 36);
643
  define ('AI_CHECK_PARAGRAPHS_AFTER_MIN_MAX_WORDS', 37);
644
  define ('AI_CHECK_PARAGRAPHS_AFTER_TEXT', 38);
645
  define ('AI_CHECK_PARAGRAPHS_AFTER_CLEARANCE', 39);
@@ -704,6 +704,7 @@ define ('AI_CLOSE_BUTTONS', 26);
704
  define ('AI_DISABLE_CACHING', 27);
705
  define ('AI_COUNT', 28);
706
  define ('AI_CLIENT_SIDE_INSERTION', 29);
 
707
 
708
  define ('AI_CONTEXT_NONE', 0);
709
  define ('AI_CONTEXT_CONTENT', 1);
@@ -758,6 +759,7 @@ define ('AI_DEBUG_POSITIONS_CLASS', 'ai-debug-positions');
758
  define ('AI_DEBUG_PAGE_TYPE_CLASS', 'ai-debug-page-type');
759
  define ('AI_DEBUG_STATUS_CLASS', 'ai-debug-status');
760
  define ('AI_DEBUG_ADB_CLASS', 'ai-debug-adb');
 
761
 
762
  define ('AI_CODE_UNKNOWN', 100);
763
  define ('AI_CODE_BANNER', 0);
@@ -774,6 +776,10 @@ define ('AI_ADSENSE_AMP_DISABLED', 0);
774
  define ('AI_ADSENSE_AMP_ABOVE_THE_FOLD', 1);
775
  define ('AI_ADSENSE_AMP_BELOW_THE_FOLD', 2);
776
 
 
 
 
 
777
  define ('AI_TEXT_LINK', 'Link');
778
  define ('AI_TEXT_IN_ARTICLE', 'In-article');
779
  define ('AI_TEXT_IN_FEED', 'In-feed');
@@ -781,3 +787,7 @@ define ('AI_TEXT_MATCHED_CONTENT', 'Matched content');
781
 
782
  define ('AI_TEXT_ABOVE_THE_FOLD', 'Above the fold');
783
  define ('AI_TEXT_BELOW_THE_FOLD', 'Below the fold');
 
 
 
 
24
  define ('AD_INSERTER_NAME', 'Ad Inserter');
25
 
26
  if (!defined( 'AD_INSERTER_VERSION'))
27
+ define ('AD_INSERTER_VERSION', '2.3.2');
28
 
29
  if (!defined ('AD_INSERTER_PLUGIN_BASENAME'))
30
  define ('AD_INSERTER_PLUGIN_BASENAME', plugin_basename (__FILE__));
639
  define ('AI_CHECK_DEBUG_NO_INSERTION', 33);
640
  define ('AI_CHECK_PARAGRAPH_TAGS', 34);
641
  define ('AI_CHECK_PARAGRAPHS_WITH_TAGS', 35);
642
+ define ('AI_CHECK_PARAGRAPHS_AFTER_NO_COUNTING_INSIDE', 36);
643
  define ('AI_CHECK_PARAGRAPHS_AFTER_MIN_MAX_WORDS', 37);
644
  define ('AI_CHECK_PARAGRAPHS_AFTER_TEXT', 38);
645
  define ('AI_CHECK_PARAGRAPHS_AFTER_CLEARANCE', 39);
704
  define ('AI_DISABLE_CACHING', 27);
705
  define ('AI_COUNT', 28);
706
  define ('AI_CLIENT_SIDE_INSERTION', 29);
707
+ define ('AI_USER_AGENT', 30);
708
 
709
  define ('AI_CONTEXT_NONE', 0);
710
  define ('AI_CONTEXT_CONTENT', 1);
759
  define ('AI_DEBUG_PAGE_TYPE_CLASS', 'ai-debug-page-type');
760
  define ('AI_DEBUG_STATUS_CLASS', 'ai-debug-status');
761
  define ('AI_DEBUG_ADB_CLASS', 'ai-debug-adb');
762
+ define ('AI_ADSENSE_BLOCK_CLASS', 'ai-adsense-');
763
 
764
  define ('AI_CODE_UNKNOWN', 100);
765
  define ('AI_CODE_BANNER', 0);
776
  define ('AI_ADSENSE_AMP_ABOVE_THE_FOLD', 1);
777
  define ('AI_ADSENSE_AMP_BELOW_THE_FOLD', 2);
778
 
779
+ define ('AI_ADSENSE_SIZE_FIXED', 0);
780
+ define ('AI_ADSENSE_SIZE_RESPONSIVE', 1);
781
+ define ('AI_ADSENSE_SIZE_FIXED_BY_VIEWPORT', 2);
782
+
783
  define ('AI_TEXT_LINK', 'Link');
784
  define ('AI_TEXT_IN_ARTICLE', 'In-article');
785
  define ('AI_TEXT_IN_FEED', 'In-feed');
787
 
788
  define ('AI_TEXT_ABOVE_THE_FOLD', 'Above the fold');
789
  define ('AI_TEXT_BELOW_THE_FOLD', 'Below the fold');
790
+
791
+ define ('AI_TEXT_FIXED', 'Fixed');
792
+ define ('AI_TEXT_RESPONSIVE', 'Responsive');
793
+ define ('AI_TEXT_FIXED_BY_VIEWPORT', 'Fixed by viewport');
css/ad-inserter.css CHANGED
@@ -1,5 +1,5 @@
1
  #ai-data {
2
- font-family: "2.3.1"; /* Used for version number of the file */
3
  }
4
 
5
  #blocked-warning {
@@ -101,6 +101,16 @@ a.clear-link, a.clear-link:hover, a.clear-link:focus {
101
  border-spacing: 4px;
102
  }
103
 
 
 
 
 
 
 
 
 
 
 
104
  .ai-settings-table.ai-values td:first-child {
105
  width: 35%;
106
  }
@@ -972,6 +982,24 @@ img.automatic-insertion.preview {
972
  line-height: 16px;
973
  }
974
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
975
  @media (max-width: 782px) {
976
  .auto-fold #wpcontent {
977
  padding-left: 4px;
@@ -1014,6 +1042,14 @@ img.automatic-insertion.preview {
1014
  margin: 6px 0 0 4px;
1015
  padding: 0px 4px 2px 0px;
1016
  }
 
 
 
 
 
 
 
 
1017
  }
1018
 
1019
  @media(max-width: 768px) {
@@ -1041,20 +1077,19 @@ img.automatic-insertion.preview {
1041
  font-size: 12px!important;
1042
  line-height: 18px;
1043
  }
1044
- /* .checkbox-icon.icon-enabled-all {*/
1045
- /* width: 20px;*/
1046
- /* height: 20px;*/
1047
- /* background: url('images/icons.png') -140px -20px;*/
1048
- /* }*/
1049
-
1050
- /* .checkbox-icon.icon-enabled-all.on {*/
1051
- /* background: url('images/icons.png') -140px -0px;*/
1052
- /* }*/
1053
 
1054
  .banner-preview img {
1055
  max-width: 160px;
1056
  max-height: 160px;
1057
  }
 
 
 
 
 
 
 
 
1058
  }
1059
 
1060
  @media(min-width: 769px) {
1
  #ai-data {
2
+ font-family: "2.3.2"; /* Used for version number of the file */
3
  }
4
 
5
  #blocked-warning {
101
  border-spacing: 4px;
102
  }
103
 
104
+ .ai-settings-table.left {
105
+ float: left;
106
+ width: 52%
107
+ }
108
+
109
+ .ai-settings-table.right {
110
+ float: right;
111
+ width: 48%
112
+ }
113
+
114
  .ai-settings-table.ai-values td:first-child {
115
  width: 35%;
116
  }
982
  line-height: 16px;
983
  }
984
 
985
+ .ad-size .scombobox {
986
+ width: 80px;
987
+ display: inline-block;
988
+ margin: 1px 0;
989
+ }
990
+
991
+ .scombobox-list p:hover, .scombobox-list p.scombobox-hovered {
992
+ background-color: #eaeaea;
993
+ }
994
+
995
+ .scombobox-list p {
996
+ padding: 1px;
997
+ }
998
+
999
+ .scombobox-display {
1000
+ padding-right: 1px;
1001
+ }
1002
+
1003
  @media (max-width: 782px) {
1004
  .auto-fold #wpcontent {
1005
  padding-left: 4px;
1042
  margin: 6px 0 0 4px;
1043
  padding: 0px 4px 2px 0px;
1044
  }
1045
+
1046
+ .ad-size .scombobox {
1047
+ width: 100px;
1048
+ }
1049
+
1050
+ .scombobox-list p {
1051
+ font-size: 16px;
1052
+ }
1053
  }
1054
 
1055
  @media(max-width: 768px) {
1077
  font-size: 12px!important;
1078
  line-height: 18px;
1079
  }
 
 
 
 
 
 
 
 
 
1080
 
1081
  .banner-preview img {
1082
  max-width: 160px;
1083
  max-height: 160px;
1084
  }
1085
+
1086
+ .ai-settings-table.left {
1087
+ width: 60%
1088
+ }
1089
+
1090
+ .ai-settings-table.right {
1091
+ width: 40%
1092
+ }
1093
  }
1094
 
1095
  @media(min-width: 769px) {
css/jquery.scombobox.css ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .scombobox {
2
+ position: relative;
3
+ margin: 5px;
4
+ }
5
+ .scombobox select {
6
+ display: none;
7
+ }
8
+
9
+ .scombobox-display {
10
+ width: 100%;
11
+ height: 100%;
12
+ padding: 2px 19px 2px 4px;
13
+ border: 1px solid #CCC;
14
+ border-radius: 4px;
15
+ box-sizing: border-box;
16
+ -moz-box-sizing: border-box;
17
+ }
18
+ .scombobox-display:focus {
19
+ box-shadow: 0 0 3px #CCC;
20
+ outline: none;
21
+ }
22
+ .scombobox-display:disabled {
23
+ background: #F0F0F0;
24
+ }
25
+ .scombobox-display.scombobox-invalid {
26
+ background: #FFCCD4;
27
+ }
28
+ .scombobox-display-div {
29
+ border: 1px solid #CCC;
30
+ border-radius: 4px;
31
+ cursor: pointer;
32
+ }
33
+ .scombobox-display-div-holder {
34
+ padding: 2px;
35
+ }
36
+ .scombobox-display-div-item {
37
+ border: 1px solid #CCC;
38
+ margin: 2px;
39
+ border-radius: 4px;
40
+ float: left;
41
+ height: 100%;
42
+ max-width: 150px;
43
+ padding: 4px 18px 4px 8px;
44
+ position: relative;
45
+ vertical-align: middle;
46
+ white-space: nowrap;
47
+ overflow: hidden;
48
+ cursor: default;
49
+ background: #F8F8F8;
50
+ display: none;
51
+ }
52
+ .scombobox-display-div-item-text {
53
+ max-width: 140px;
54
+ overflow: hidden;
55
+ }
56
+ .scombobox-display-div-item-remove {
57
+ position: absolute;
58
+ right: 2px; top: 2px;
59
+ background: #A0A0A0;
60
+ border-radius: 100px;
61
+ color: white;
62
+ cursor: pointer;
63
+ line-height: 90%;
64
+ padding: 1px 3px 0px;
65
+ }
66
+ .scombobox-display-div-item-remove:hover {
67
+ background: #408CBE;
68
+ }
69
+ .scombobox-display-div-item-remove:active {
70
+ background: #3075A3;
71
+ }
72
+
73
+ .scombobox-list {
74
+ display: none;
75
+ position: absolute;
76
+ max-height: 400px;
77
+ min-width: 100%;
78
+ max-width: 300%;
79
+ white-space: nowrap;
80
+ box-sizing: border-box;
81
+ -moz-box-sizing: border-box;
82
+ overflow-y: auto;
83
+ background: white;
84
+ border: 1px solid #CCC;
85
+ border-top: none; /* instead of margin-top: -1px */
86
+ border-radius: 4px;
87
+ box-shadow: 0 0 3px #CCC;
88
+ z-index: 10;
89
+ }
90
+ .scombobox-list p {
91
+ cursor: pointer;
92
+ margin: 0;
93
+ padding: 5px;
94
+ }
95
+ .scombobox-list p input[type="checkbox"] {
96
+ margin-right: 8px;
97
+ vertical-align: middle;
98
+ }
99
+ .scombobox-list p:hover, .scombobox-list p.scombobox-hovered {
100
+ background-color: #E9EFFC;
101
+ }
102
+ .scombobox-list p.scombobox-separator {
103
+ height: 2px; padding: 0; cursor: default; background: #EEE;
104
+ }
105
+ .scombobox-list p.scombobox-header {
106
+ cursor: default;
107
+ background: #EEE;
108
+ }
109
+
110
+ .scombobox-dropdown-arrow {
111
+ position: absolute;
112
+ top: 0;
113
+ right: 0;
114
+ width: 20px;
115
+ height: 100%;
116
+ /* background size: 4 Kb */
117
+ background: url(data:image/png;base64,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) center no-repeat;
118
+ z-index: 1;
119
+ opacity: 0.85;
120
+ filter:alpha(opacity=85);
121
+ cursor: pointer;
122
+ }
123
+ .scombobox-dropdown-arrow:hover {
124
+ opacity: 1;
125
+ filter:alpha(opacity=100);
126
+ }
127
+ .scombobox-dropdown-arrow-up {
128
+ /* background size: 4 Kb */
129
+ background: url(data:image/png;base64,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) center no-repeat;
130
+ }
131
+ .scombobox-dropdown-background {
132
+ position: absolute;
133
+ top: 0;
134
+ right: 0;
135
+ width: 20px;
136
+ height: 100%;
137
+ background: white;
138
+ border: 1px solid #CCC;
139
+ border-radius: 0 4px 4px 0;
140
+ border-left: none;
141
+ box-sizing: border-box;
142
+ -moz-box-sizing: border-box;
143
+ }
144
+ .scombobox-dropdown-background-invalid {
145
+ border-left: 1px solid #CCC;
146
+ }
147
+
148
+ .scombobox-marker {
149
+ background: #958FFF;
150
+ color: white;
151
+ border-radius: 2px;
152
+ padding: 0 2px;
153
+ margin: 0 2px;
154
+ }
155
+
156
+ .scombobox input[type="checkbox"] {
157
+ cursor: pointer;
158
+ }
159
+
160
+ .scombobox-disabled .scombobox-dropdown-background,
161
+ .scombobox-disabled .scombobox-dropdown-arrow {
162
+ display: none;
163
+ }
164
+ .scombobox-disabled .scombobox-display-div {
165
+ background: #F8F8F8;
166
+ cursor: default;
167
+ }
css/jquery.scombobox.min.css ADDED
@@ -0,0 +1 @@
 
1
+ .scombobox{margin:5px;position:relative}.scombobox-display{-moz-box-sizing:border-box;border:1px solid #CCC;border-radius:4px;box-sizing:border-box;height:100%;padding:2px 19px 2px 4px;width:100%}.scombobox-display:focus{box-shadow:0 0 3px #CCC;outline:none}.scombobox-display:disabled{background:#F0F0F0}.scombobox-display.scombobox-invalid{background:#FFCCD4}.scombobox-display-div{border:1px solid #CCC;border-radius:4px;cursor:pointer}.scombobox-display-div-holder{padding:2px}.scombobox-display-div-item{background:#F8F8F8;border:1px solid #CCC;border-radius:4px;cursor:default;display:none;float:left;height:100%;margin:2px;max-width:150px;overflow:hidden;padding:4px 18px 4px 8px;position:relative;vertical-align:middle;white-space:nowrap}.scombobox-display-div-item-text{max-width:140px;overflow:hidden}.scombobox-display-div-item-remove{background:#A0A0A0;border-radius:100px;color:#FFF;cursor:pointer;line-height:90%;padding:1px 3px 0;position:absolute;right:2px;top:2px}.scombobox-display-div-item-remove:hover{background:#408CBE}.scombobox-display-div-item-remove:active{background:#3075A3}.scombobox-list{-moz-box-sizing:border-box;background:#FFF;border:1px solid #CCC;border-radius:4px;border-top:none;box-shadow:0 0 3px #CCC;box-sizing:border-box;display:none;max-height:400px;max-width:300%;min-width:100%;overflow-y:auto;position:absolute;white-space:nowrap;z-index:10}.scombobox-list p{cursor:pointer;margin:0;padding:5px}.scombobox-list p input[type=checkbox]{margin-right:8px;vertical-align: middle;}.scombobox-list p:hover,.scombobox-list p.scombobox-hovered{background-color:#E9EFFC}.scombobox-list p.scombobox-separator{background:#EEE;cursor:default;height:2px;padding:0}.scombobox-list p.scombobox-header{background:#EEE;cursor:default}.scombobox-dropdown-arrow{background:url(data:image/png;base64,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) center no-repeat;cursor:pointer;filter:alpha(opacity=85);height:100%;opacity:0.85;position:absolute;right:0;top:0;width:20px;z-index:1}.scombobox-dropdown-arrow:hover{filter:alpha(opacity=100);opacity:1}.scombobox-dropdown-arrow-up{background:url(data:image/png;base64,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) center no-repeat}.scombobox-dropdown-background{-moz-box-sizing:border-box;background:#FFF;border:1px solid #CCC;border-left:none;border-radius:0 4px 4px 0;box-sizing:border-box;height:100%;position:absolute;right:0;top:0;width:20px}.scombobox-dropdown-background-invalid{border-left:1px solid #CCC}.scombobox-marker{background:#958FFF;border-radius:2px;color:#FFF;margin:0 2px;padding:0 2px}.scombobox input[type=checkbox]{cursor:pointer}.scombobox-disabled .scombobox-display-div{background:#F8F8F8;cursor:default}.scombobox select,.scombobox-disabled .scombobox-dropdown-background,.scombobox-disabled .scombobox-dropdown-arrow{display:none}
includes/js/ai-insert.js CHANGED
@@ -1,71 +1,226 @@
1
- function ai_insert (insertion, selector, insertion_code) {
2
- jQuery (selector).each (function (index, element) {
3
-
4
- if (typeof jQuery(this).attr ('id') != 'undefined') {
5
- selector_string = '#' + jQuery(this).attr ('id');
6
- } else
7
- if (typeof jQuery(this).attr ('class') != 'undefined') {
8
- selector_string = '.' + jQuery(this).attr ('class').replace (' ', '.');
9
- } else
10
- selector_string = '';
11
-
12
- var insertion_function = insertion;
13
- var ai_code = jQuery (insertion_code);
14
-
15
- jQuery ('.ai-selector-counter', ai_code).text (index + 1);
16
- jQuery ('.ai-debug-name.ai-main', ai_code).text (insertion.toUpperCase () + ' ' + jQuery(this).prop ('tagName').toLowerCase() + selector_string);
17
-
18
- jQuery(this)[insertion_function] (ai_code);
19
- });
20
- }
21
-
22
- function ai_insert_viewport (element) {
23
-
24
- var ai_debug = typeof ai_debugging !== 'undefined';
25
-
26
- if (ai_debug) console.log ('AI VIEWPORT INSERTION: class', element.attr ('class'));
27
-
28
- var visible = element.is(':visible');
29
- var block = element.data ('block');
30
-
31
- if (visible) {
32
- var insertion_code = element.data ('code');
33
- var insertion_type = element.data ('insertion');
34
- var selector = element.data ('selector');
35
-
36
- if (typeof insertion_code != 'undefined') {
37
- if (typeof insertion_type != 'undefined' && typeof selector != 'undefined') {
38
-
39
- var selector_exists = jQuery (selector).length
40
- if (ai_debug) console.log ('AI VIEWPORT VISIBLE: block', block, insertion_type, selector, selector_exists ? '' : 'NOT FOUND');
41
-
42
- ai_insert (insertion_type, selector, atob (insertion_code));
43
- if (selector_exists) element.removeClass ('ai-viewports');
44
- } else {
45
-
46
- if (ai_debug) console.log ('AI VIEWPORT VISIBLE: block', block);
47
-
48
- var ai_code = jQuery(atob (insertion_code));
49
- element.after (ai_code);
50
- element.removeClass ('ai-viewports');
51
- }
52
- }
53
- } else {
54
- if (ai_debug) console.log ('AI VIEWPORT NOT VISIBLE: block', block);
55
-
56
- var debug_bar = element.prev ();
57
- if (debug_bar.hasClass ('ai-debug-bar') && debug_bar.hasClass ('ai-debug-script')) {
58
- debug_bar.removeClass ('ai-debug-script')
59
- debug_bar.addClass ('ai-debug-viewport-invisible')
60
- }
61
- }
62
- }
63
-
64
- (function($){
65
- // Insert remaining elements that depend on viewports
66
- $(document).ready (function() {
67
- $('.ai-viewports').each (function (index, element) {
68
- ai_insert_viewport ($(this));
69
- });
70
- });
71
- })(jQuery);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function ai_insert (insertion, selector, insertion_code) {
2
+ jQuery (selector).each (function (index, element) {
3
+
4
+ if (typeof jQuery(this).attr ('id') != 'undefined') {
5
+ selector_string = '#' + jQuery(this).attr ('id');
6
+ } else
7
+ if (typeof jQuery(this).attr ('class') != 'undefined') {
8
+ selector_string = '.' + jQuery(this).attr ('class').replace (' ', '.');
9
+ } else
10
+ selector_string = '';
11
+
12
+ var insertion_function = insertion;
13
+ var ai_code = jQuery (insertion_code);
14
+
15
+ jQuery ('.ai-selector-counter', ai_code).text (index + 1);
16
+ jQuery ('.ai-debug-name.ai-main', ai_code).text (insertion.toUpperCase () + ' ' + jQuery(this).prop ('tagName').toLowerCase() + selector_string);
17
+
18
+ jQuery(this)[insertion_function] (ai_code);
19
+ });
20
+ }
21
+
22
+ function ai_insert_viewport (element) {
23
+
24
+ var ai_debug = typeof ai_debugging !== 'undefined';
25
+
26
+ if (ai_debug) console.log ('AI VIEWPORT INSERTION: class', element.attr ('class'));
27
+
28
+ var visible = element.is(':visible');
29
+ var block = element.data ('block');
30
+
31
+ if (visible) {
32
+ var insertion_code = element.data ('code');
33
+ var insertion_type = element.data ('insertion');
34
+ var selector = element.data ('selector');
35
+
36
+ if (typeof insertion_code != 'undefined') {
37
+ if (typeof insertion_type != 'undefined' && typeof selector != 'undefined') {
38
+
39
+ var selector_exists = jQuery (selector).length
40
+ if (ai_debug) console.log ('AI VIEWPORT VISIBLE: block', block, insertion_type, selector, selector_exists ? '' : 'NOT FOUND');
41
+
42
+ ai_insert (insertion_type, selector, jQuery.base64Decode (insertion_code));
43
+ if (selector_exists) element.removeClass ('ai-viewports');
44
+ } else {
45
+
46
+ if (ai_debug) console.log ('AI VIEWPORT VISIBLE: block', block);
47
+
48
+ var ai_code = jQuery(jQuery.base64Decode (insertion_code));
49
+ element.after (ai_code);
50
+ element.removeClass ('ai-viewports');
51
+ }
52
+ }
53
+ } else {
54
+ if (ai_debug) console.log ('AI VIEWPORT NOT VISIBLE: block', block);
55
+
56
+ var debug_bar = element.prev ();
57
+ if (debug_bar.hasClass ('ai-debug-bar') && debug_bar.hasClass ('ai-debug-script')) {
58
+ debug_bar.removeClass ('ai-debug-script')
59
+ debug_bar.addClass ('ai-debug-viewport-invisible')
60
+ }
61
+ }
62
+ }
63
+
64
+ (function($){
65
+ // Insert remaining elements that depend on viewports
66
+ $(document).ready (function() {
67
+ $('.ai-viewports').each (function (index, element) {
68
+ ai_insert_viewport ($(this));
69
+ });
70
+ });
71
+ })(jQuery);
72
+
73
+
74
+ (function($){
75
+ // Insert remaining elements that depend on viewports
76
+ $(document).ready (function() {
77
+ $('.ai-viewports').each (function (index, element) {
78
+ ai_insert_viewport ($(this));
79
+ });
80
+ });
81
+ })(jQuery);
82
+
83
+ /**
84
+ * jQuery BASE64 functions
85
+ *
86
+ * <code>
87
+ * Encodes the given data with base64.
88
+ * String $.base64Encode ( String str )
89
+ * <br />
90
+ * Decodes a base64 encoded data.
91
+ * String $.base64Decode ( String str )
92
+ * </code>
93
+ *
94
+ * Encodes and Decodes the given data in base64.
95
+ * This encoding is designed to make binary data survive transport through transport layers that are not 8-bit clean, such as mail bodies.
96
+ * Base64-encoded data takes about 33% more space than the original data.
97
+ * This javascript code is used to encode / decode data using base64 (this encoding is designed to make binary data survive transport through transport layers that are not 8-bit clean). Script is fully compatible with UTF-8 encoding. You can use base64 encoded data as simple encryption mechanism.
98
+ * If you plan using UTF-8 encoding in your project don't forget to set the page encoding to UTF-8 (Content-Type meta tag).
99
+ * This function orginally get from the WebToolkit and rewrite for using as the jQuery plugin.
100
+ *
101
+ * Example
102
+ * Code
103
+ * <code>
104
+ * $.base64Encode("I'm Persian.");
105
+ * </code>
106
+ * Result
107
+ * <code>
108
+ * "SSdtIFBlcnNpYW4u"
109
+ * </code>
110
+ * Code
111
+ * <code>
112
+ * $.base64Decode("SSdtIFBlcnNpYW4u");
113
+ * </code>
114
+ * Result
115
+ * <code>
116
+ * "I'm Persian."
117
+ * </code>
118
+ *
119
+ * @alias Muhammad Hussein Fattahizadeh < muhammad [AT] semnanweb [DOT] com >
120
+ * @link http://www.semnanweb.com/jquery-plugin/base64.html (no longer available?)
121
+ * @link https://gist.github.com/gists/1602210
122
+ * @see http://www.webtoolkit.info/
123
+ * @license http://www.gnu.org/licenses/gpl.html [GNU General Public License]
124
+ * @param {jQuery} {base64Encode:function(input))
125
+ * @param {jQuery} {base64Decode:function(input))
126
+ * @return string
127
+ */
128
+
129
+ (function($){
130
+
131
+ var keyString = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
132
+
133
+ var uTF8Encode = function(string) {
134
+ string = string.replace(/\x0d\x0a/g, "\x0a");
135
+ var output = "";
136
+ for (var n = 0; n < string.length; n++) {
137
+ var c = string.charCodeAt(n);
138
+ if (c < 128) {
139
+ output += String.fromCharCode(c);
140
+ } else if ((c > 127) && (c < 2048)) {
141
+ output += String.fromCharCode((c >> 6) | 192);
142
+ output += String.fromCharCode((c & 63) | 128);
143
+ } else {
144
+ output += String.fromCharCode((c >> 12) | 224);
145
+ output += String.fromCharCode(((c >> 6) & 63) | 128);
146
+ output += String.fromCharCode((c & 63) | 128);
147
+ }
148
+ }
149
+ return output;
150
+ };
151
+
152
+ var uTF8Decode = function(input) {
153
+ var string = "";
154
+ var i = 0;
155
+ var c = c1 = c2 = 0;
156
+ while ( i < input.length ) {
157
+ c = input.charCodeAt(i);
158
+ if (c < 128) {
159
+ string += String.fromCharCode(c);
160
+ i++;
161
+ } else if ((c > 191) && (c < 224)) {
162
+ c2 = input.charCodeAt(i+1);
163
+ string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
164
+ i += 2;
165
+ } else {
166
+ c2 = input.charCodeAt(i+1);
167
+ c3 = input.charCodeAt(i+2);
168
+ string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
169
+ i += 3;
170
+ }
171
+ }
172
+ return string;
173
+ }
174
+
175
+ $.extend({
176
+ base64Encode: function(input) {
177
+ var output = "";
178
+ var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
179
+ var i = 0;
180
+ input = uTF8Encode(input);
181
+ while (i < input.length) {
182
+ chr1 = input.charCodeAt(i++);
183
+ chr2 = input.charCodeAt(i++);
184
+ chr3 = input.charCodeAt(i++);
185
+ enc1 = chr1 >> 2;
186
+ enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
187
+ enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
188
+ enc4 = chr3 & 63;
189
+ if (isNaN(chr2)) {
190
+ enc3 = enc4 = 64;
191
+ } else if (isNaN(chr3)) {
192
+ enc4 = 64;
193
+ }
194
+ output = output + keyString.charAt(enc1) + keyString.charAt(enc2) + keyString.charAt(enc3) + keyString.charAt(enc4);
195
+ }
196
+ return output;
197
+ },
198
+ base64Decode: function(input) {
199
+ var output = "";
200
+ var chr1, chr2, chr3;
201
+ var enc1, enc2, enc3, enc4;
202
+ var i = 0;
203
+ input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
204
+ while (i < input.length) {
205
+ enc1 = keyString.indexOf(input.charAt(i++));
206
+ enc2 = keyString.indexOf(input.charAt(i++));
207
+ enc3 = keyString.indexOf(input.charAt(i++));
208
+ enc4 = keyString.indexOf(input.charAt(i++));
209
+ chr1 = (enc1 << 2) | (enc2 >> 4);
210
+ chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
211
+ chr3 = ((enc3 & 3) << 6) | enc4;
212
+ output = output + String.fromCharCode(chr1);
213
+ if (enc3 != 64) {
214
+ output = output + String.fromCharCode(chr2);
215
+ }
216
+ if (enc4 != 64) {
217
+ output = output + String.fromCharCode(chr3);
218
+ }
219
+ }
220
+ output = uTF8Decode(output);
221
+ return output;
222
+ }
223
+ });
224
+ })(jQuery);
225
+
226
+
includes/js/ai-insert.min.js CHANGED
@@ -1,5 +1,15 @@
 
 
 
 
 
 
1
  function ai_insert(insertion,selector,insertion_code){jQuery(selector).each(function(index,element){if(typeof jQuery(this).attr("id")!="undefined")selector_string="#"+jQuery(this).attr("id");else if(typeof jQuery(this).attr("class")!="undefined")selector_string="."+jQuery(this).attr("class").replace(" ",".");else selector_string="";var insertion_function=insertion;var ai_code=jQuery(insertion_code);jQuery(".ai-selector-counter",ai_code).text(index+1);jQuery(".ai-debug-name.ai-main",ai_code).text(insertion.toUpperCase()+
2
  " "+jQuery(this).prop("tagName").toLowerCase()+selector_string);jQuery(this)[insertion_function](ai_code)})}
3
  function ai_insert_viewport(element){var ai_debug=typeof ai_debugging!=="undefined";if(ai_debug)console.log("AI VIEWPORT INSERTION: class",element.attr("class"));var visible=element.is(":visible");var block=element.data("block");if(visible){var insertion_code=element.data("code");var insertion_type=element.data("insertion");var selector=element.data("selector");if(typeof insertion_code!="undefined")if(typeof insertion_type!="undefined"&&typeof selector!="undefined"){var selector_exists=jQuery(selector).length;
4
- if(ai_debug)console.log("AI VIEWPORT VISIBLE: block",block,insertion_type,selector,selector_exists?"":"NOT FOUND");ai_insert(insertion_type,selector,atob(insertion_code));if(selector_exists)element.removeClass("ai-viewports")}else{if(ai_debug)console.log("AI VIEWPORT VISIBLE: block",block);var ai_code=jQuery(atob(insertion_code));element.after(ai_code);element.removeClass("ai-viewports")}}else{if(ai_debug)console.log("AI VIEWPORT NOT VISIBLE: block",block);var debug_bar=element.prev();if(debug_bar.hasClass("ai-debug-bar")&&
5
- debug_bar.hasClass("ai-debug-script")){debug_bar.removeClass("ai-debug-script");debug_bar.addClass("ai-debug-viewport-invisible")}}}(function($){$(document).ready(function(){$(".ai-viewports").each(function(index,element){ai_insert_viewport($(this))})})})(jQuery);
 
 
 
 
1
+ /*
2
+ http://www.gnu.org/licenses/gpl.html [GNU General Public License]
3
+ @param {jQuery} {base64Encode:function(input))
4
+ @param {jQuery} {base64Decode:function(input))
5
+ @return string
6
+ */
7
  function ai_insert(insertion,selector,insertion_code){jQuery(selector).each(function(index,element){if(typeof jQuery(this).attr("id")!="undefined")selector_string="#"+jQuery(this).attr("id");else if(typeof jQuery(this).attr("class")!="undefined")selector_string="."+jQuery(this).attr("class").replace(" ",".");else selector_string="";var insertion_function=insertion;var ai_code=jQuery(insertion_code);jQuery(".ai-selector-counter",ai_code).text(index+1);jQuery(".ai-debug-name.ai-main",ai_code).text(insertion.toUpperCase()+
8
  " "+jQuery(this).prop("tagName").toLowerCase()+selector_string);jQuery(this)[insertion_function](ai_code)})}
9
  function ai_insert_viewport(element){var ai_debug=typeof ai_debugging!=="undefined";if(ai_debug)console.log("AI VIEWPORT INSERTION: class",element.attr("class"));var visible=element.is(":visible");var block=element.data("block");if(visible){var insertion_code=element.data("code");var insertion_type=element.data("insertion");var selector=element.data("selector");if(typeof insertion_code!="undefined")if(typeof insertion_type!="undefined"&&typeof selector!="undefined"){var selector_exists=jQuery(selector).length;
10
+ if(ai_debug)console.log("AI VIEWPORT VISIBLE: block",block,insertion_type,selector,selector_exists?"":"NOT FOUND");ai_insert(insertion_type,selector,jQuery.base64Decode(insertion_code));if(selector_exists)element.removeClass("ai-viewports")}else{if(ai_debug)console.log("AI VIEWPORT VISIBLE: block",block);var ai_code=jQuery(jQuery.base64Decode(insertion_code));element.after(ai_code);element.removeClass("ai-viewports")}}else{if(ai_debug)console.log("AI VIEWPORT NOT VISIBLE: block",block);var debug_bar=
11
+ element.prev();if(debug_bar.hasClass("ai-debug-bar")&&debug_bar.hasClass("ai-debug-script")){debug_bar.removeClass("ai-debug-script");debug_bar.addClass("ai-debug-viewport-invisible")}}}(function($){$(document).ready(function(){$(".ai-viewports").each(function(index,element){ai_insert_viewport($(this))})})})(jQuery);(function($){$(document).ready(function(){$(".ai-viewports").each(function(index,element){ai_insert_viewport($(this))})})})(jQuery);
12
+ (function($){var keyString="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var uTF8Encode=function(string){string=string.replace(/\x0d\x0a/g,"\n");var output="";for(var n=0;n<string.length;n++){var c=string.charCodeAt(n);if(c<128)output+=String.fromCharCode(c);else if(c>127&&c<2048){output+=String.fromCharCode(c>>6|192);output+=String.fromCharCode(c&63|128)}else{output+=String.fromCharCode(c>>12|224);output+=String.fromCharCode(c>>6&63|128);output+=String.fromCharCode(c&63|128)}}return output};
13
+ var uTF8Decode=function(input){var string="";var i=0;var c=c1=c2=0;while(i<input.length){c=input.charCodeAt(i);if(c<128){string+=String.fromCharCode(c);i++}else if(c>191&&c<224){c2=input.charCodeAt(i+1);string+=String.fromCharCode((c&31)<<6|c2&63);i+=2}else{c2=input.charCodeAt(i+1);c3=input.charCodeAt(i+2);string+=String.fromCharCode((c&15)<<12|(c2&63)<<6|c3&63);i+=3}}return string};$.extend({base64Encode:function(input){var output="";var chr1,chr2,chr3,enc1,enc2,enc3,enc4;var i=0;input=uTF8Encode(input);
14
+ while(i<input.length){chr1=input.charCodeAt(i++);chr2=input.charCodeAt(i++);chr3=input.charCodeAt(i++);enc1=chr1>>2;enc2=(chr1&3)<<4|chr2>>4;enc3=(chr2&15)<<2|chr3>>6;enc4=chr3&63;if(isNaN(chr2))enc3=enc4=64;else if(isNaN(chr3))enc4=64;output=output+keyString.charAt(enc1)+keyString.charAt(enc2)+keyString.charAt(enc3)+keyString.charAt(enc4)}return output},base64Decode:function(input){var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;input=input.replace(/[^A-Za-z0-9\+\/=]/g,"");while(i<
15
+ input.length){enc1=keyString.indexOf(input.charAt(i++));enc2=keyString.indexOf(input.charAt(i++));enc3=keyString.indexOf(input.charAt(i++));enc4=keyString.indexOf(input.charAt(i++));chr1=enc1<<2|enc2>>4;chr2=(enc2&15)<<4|enc3>>2;chr3=(enc3&3)<<6|enc4;output=output+String.fromCharCode(chr1);if(enc3!=64)output=output+String.fromCharCode(chr2);if(enc4!=64)output=output+String.fromCharCode(chr3)}output=uTF8Decode(output);return output}})})(jQuery);
includes/js/jquery.scombobox.js ADDED
@@ -0,0 +1,1505 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * jquery.simple-combobox v1.1.26 (2015-11-05): jQuery combobox plugin | (c) 2014-2015 Ilya Kremer
3
+ * MIT license http://www.opensource.org/licenses/mit-license.php
4
+ */
5
+
6
+ // Fill free to use this jQuery plugin in any projects you want
7
+ // while keeping the comment above on top of the script.
8
+ // Don't forget not to remove it from a minimised version also.
9
+ // Thank you!
10
+
11
+ // TODO consider to use markup when filling combobox from original select options
12
+ // TODO consider to add fadeout background for items (checkboxes mode)
13
+ // TODO implement items removal (for infinite number of items)
14
+
15
+ /**
16
+ * Original plugin structure taken and extended from http://stackoverflow.com/a/6871820/837165
17
+ * See and change default options at the end of the code or use
18
+ * $.scombobox.extendDefaults(options) method if you don't feel like
19
+ * touching the original plugin source code.
20
+ * This plugin uses following JS native methods:
21
+ *
22
+ * String.prototype.trim()
23
+ * Array.prototype.indexOf()
24
+ * Object.keys()
25
+ * console object
26
+ *
27
+ * so don't forget to add them to your project for better browser compatibility.
28
+ * You can use missed.js file for that purpose from original GitHub project:
29
+ * https://github.com/ivkremer/jquery-simple-combobox
30
+ *
31
+ * This plugin adds click listener on document, so don't forget to check if events
32
+ * can rich it or use scombobox.close method.
33
+ * @param {Object} $ jQuery reference
34
+ * @param {Object} document (HTMLDocument)
35
+ * @returns {undefined}
36
+ */
37
+ (function($, document) {
38
+ 'use strict';
39
+ var pname = 'scombobox'; // plugin name, don't forget to change css prefixes if necessary
40
+ var cp = '.' + pname;
41
+ var cdisplay = '-display',
42
+ cvalue = '-value',
43
+ cinvalid = '-invalid',
44
+ cdiv = cdisplay + '-div',
45
+ cditem = cdiv + '-item',
46
+ cdiremove = cditem + '-remove',
47
+ cdholder = cdiv + '-holder',
48
+ clist = '-list',
49
+ cmainspan = '-mainspan',
50
+ chovered = '-hovered',
51
+ csep = '-separator',
52
+ cpheader = '-header',
53
+ cddback = '-dropdown-background',
54
+ cddarr = '-dropdown-arrow',
55
+ cdisabled = '-disabled',
56
+ crequired = '-required';
57
+
58
+ function durations(d) {
59
+ return ({
60
+ fast: 200,
61
+ normal: 400,
62
+ slow: 600
63
+ })[d] || d;
64
+ }
65
+ var pInt = parseInt;
66
+ var methods = {
67
+ /**
68
+ * Initializes the combobox.
69
+ * @returns {Object} jQuery object
70
+ */
71
+ init: function() {
72
+ var $div = this.find(cp + clist),
73
+ $select = this.find('select'),
74
+ $dropdownBack = this.find(cp + cddback),
75
+ $dropdownArr = this.find(cp + cddarr);
76
+ var opts = this.data(pname);
77
+ this.addClass(pname);
78
+ if ($select.length == 0) {
79
+ this.append($('<select />'));
80
+ }
81
+ if (this.attr('id')) {
82
+ $select.removeAttr('id');
83
+ }
84
+ if ($select.attr('multiple')) {
85
+ this.data(pname).mode = 'checkboxes';
86
+ }
87
+ if ($dropdownBack.length == 0) {
88
+ this.append('<div class="' + pname + cddback + '" />');
89
+ }
90
+ if ($dropdownArr.length == 0) {
91
+ this.append('<div class="' + pname + cddarr + '" />');
92
+ }
93
+ methods.displayDropdown.call(this, opts.showDropDown);
94
+ if (opts.mode != 'checkboxes') {
95
+ if (this.find(cp + cdisplay).length == 0) {
96
+ var $inputDisplay = $('<input class="' + pname + cdisplay + '" type="text" />');
97
+ $inputDisplay.attr('title', $select.attr('title'));
98
+ $inputDisplay.attr('placeholder', opts.placeholder);
99
+ this.append($inputDisplay);
100
+ this.height(+$inputDisplay.css('font-size') +
101
+ +$inputDisplay.css('padding-top') +
102
+ +$inputDisplay.css('padding-bottom')
103
+ );
104
+ }
105
+ }
106
+ if (opts.tabindex != null) {
107
+ this.find(cp + cdisplay).attr('tabindex', opts.tabindex);
108
+ }
109
+ if (this.find(cp + cvalue).length == 0) {
110
+ this.append('<input class="' + pname + cvalue + '" type="hidden" />');
111
+ }
112
+ if (this.find(cp + cdisplay).is(':disabled') || opts.disabled) {
113
+ this.find(cp + cddback + ', ' + cp + cddarr).hide();
114
+ }
115
+ if (opts.disabled) {
116
+ this.find(cp + cdisplay).prop('disabled', true);
117
+ this.addClass(pname + cdisabled);
118
+ }
119
+ if ($select.attr('required') || opts.required) {
120
+ this.find(cp + cdisplay).prop('required', 'required');
121
+ this.addClass(pname + crequired);
122
+ }
123
+ if ($div.length == 0) {
124
+ this.append($div = $('<div class="' + pname + clist + '"></div>'));
125
+ }
126
+ if (opts.mode == 'checkboxes') {
127
+ this.addClass(pname + '-checkboxes');
128
+ this.find(cp + cdisplay).remove();
129
+ var $displayDiv = this.find(cp + cdisplay + '-div');
130
+ if ($displayDiv.length == 0) {
131
+ $displayDiv = this.append('<div class="' + pname + cdiv + '"><div class="' + pname + cdholder + '" /></div>');
132
+ }
133
+ $displayDiv.attr('title', $select.attr('title'));
134
+ $div.insertAfter(this.find(cp + cdisplay + '-div'));
135
+ var $dholder = this.find(cp + cdholder);
136
+ var $testItem = $('<div class="' + pname + cditem + '" id="' + pname + '-test-item"><div class="' + pname + cditem + '-text">x</div></div>');
137
+ $dholder.append($testItem.css('margin-left', '-9999px').show());
138
+ var height = $testItem.height() + pInt($testItem.css('padding-top')) + pInt($testItem.css('padding-top')) + pInt($testItem.css('margin-top')) + pInt($testItem.css('margin-top')) + pInt($testItem.css('border-top-width')) + pInt($testItem.css('border-top-width')) + pInt($dholder.css('padding-top')) + pInt($dholder.css('padding-top'));
139
+ this.find(cp + cdisplay + '-div').css('min-height', height + 'px');
140
+ $testItem.remove();
141
+ } else {
142
+ this.find(cp + '-display-div').remove();
143
+ $div.insertAfter(this.find(cp + cdisplay));
144
+
145
+ }
146
+ $div.css({ 'max-width': opts.listMaxWidth, 'max-height': opts.maxHeight });
147
+ if (opts.wrap == true) {
148
+ $div.css('white-space', 'normal');
149
+ }
150
+ if (opts.autoLoad != $.noop) {
151
+ opts.loopScrolling = false; // there is no way to support this feature when auto loading more items
152
+ }
153
+ addListeners.call(this);
154
+ this.data(pname + '-init', true); // true says that it is right after initialization, it is necessary for callback
155
+ return methods.fill.call(this, opts.data); // (will be set to false after filling)
156
+ },
157
+ /**
158
+ * Fills the combobox with specified data or using options list in select if no data given.
159
+ * @see comments in defaults
160
+ * @param {Array} data array of data objects. See comments in defaults
161
+ * @param {Number} appendMode flag defining if to append (1) or prepend (2) data to existing items
162
+ * @returns {Object} jQuery object
163
+ */
164
+ fill: function(data, appendMode) {
165
+ var $options = this.find('select').children('option, optgroup');
166
+ // don't ever rely on div content, always use select options instead
167
+ var $div = this.find('.' + pname + clist),
168
+ $select = this.find('select');
169
+ data = normalizeData(data);
170
+ var opts = this.data(pname);
171
+ var mode = opts.mode;
172
+ if (!data) { // no data were given; get data from select options
173
+ if (opts.removeDuplicates) {
174
+ removeDupsjQ($options);
175
+ purifyOptions($options);
176
+ $options = this.find('select').children('option, optgroup'); // update after removal
177
+ }
178
+ if ($options.length == 0) {
179
+ // TODO restore, using $p.data(pname).key if provided instead
180
+ } else { // here are options:
181
+ $options.each(function() {
182
+ var $t = $(this);
183
+ var $p = $('<p />');
184
+ $p.attr('title', $t.attr('title'));
185
+ if ($t.hasClass(pname + csep)) { // separator, not an option
186
+ if ($t.hasClass(pname + cpheader)) { // if header text also given then add only header
187
+ $div.append($p.addClass(pname + cpheader).text($t.text()));
188
+ } else { // else add separator itself
189
+ $p.addClass(pname + csep);
190
+ }
191
+ } else if (this.tagName.toLowerCase() == 'optgroup') {
192
+ var label = $t.attr('label');
193
+ var $innerOptions = $('option', this);
194
+ $t.before('<option />'); // don't know why after doesn't work correctly
195
+ $t.after($innerOptions); // unwrap it
196
+ $t.remove(); // remove optgroup tag itself
197
+ $div.append(label ? $p.addClass(pname + cpheader).text(label) : $p.addClass(pname + csep));
198
+ $innerOptions.each(function() {
199
+ $div.append($('<p />').attr('title', this.title).append($('<span class="' + pname + cmainspan + '" />').text($(this).text())).data('value', this.value));
200
+ });
201
+ return;
202
+ } else {
203
+ $p.append($('<span class="' + pname + cmainspan + '" />').text($t.text())).data('value', this.value);
204
+ if (mode == 'checkboxes') {
205
+ $p.prepend('<input type="checkbox" />');
206
+ }
207
+ }
208
+ $div.append($p);
209
+ });
210
+ }
211
+ } else { // fill directly from given data
212
+ if (opts.removeDuplicates) {
213
+ removeDups(data);
214
+ }
215
+ purifyData(data);
216
+ if (opts.sort) {
217
+ data.sort(sortF);
218
+ if (!opts.sortAsc) {
219
+ data.reverse();
220
+ }
221
+ }
222
+ if (!appendMode) {
223
+ $select.empty();
224
+ $div.empty();
225
+ this.children(cp + cvalue + ', ' + cp + cdisplay).val('');
226
+ } // TODO consider if appendMode == 2 is not a stupid piece of code
227
+ renderItems.call(this, data, appendMode == 2); // if appendMode == 2, then it is prepend
228
+ }
229
+ if (this.data(pname + '-init')) {
230
+ opts.callback.func.apply(this, opts.callback.args);
231
+ this.data(pname + '-init', false);
232
+ }
233
+ $options = this.find('select').children('option'); // update
234
+ if (!opts.empty) {
235
+ if (mode != 'checkboxes') {
236
+ this[pname]('val', $options.filter('option:selected:last').val());
237
+ } else {
238
+ var selectedValues = $options.filter(':selected').map(function() {
239
+ return $(this).val();
240
+ }).get();
241
+ this[pname]('val', selectedValues);
242
+ }
243
+ }
244
+ return this;
245
+ },
246
+ /**
247
+ * Removes all items from combobox (html-based removal)
248
+ * @returns {Object} jQuery object
249
+ */
250
+ clear: function() { // TODO check why to or not to remove data itself
251
+ this.children('select').empty();
252
+ this.children(cp + clist).empty().width('');
253
+ this.children(cp + cdisplay).removeClass(pname + cinvalid);
254
+ this.children(cp + cddback).removeClass(pname + cddback + cinvalid);
255
+ return this;
256
+ },
257
+ /**
258
+ * Updates data without touching html items or gets the data.
259
+ * For updating combobox contents use fill method.
260
+ * @param {string} data
261
+ * @returns {Object} jQuery object
262
+ */
263
+ data: function(data) { // this method is required because after setting new options
264
+ // via options method the data will be merged which probably will be wrong
265
+ if (arguments.length == 0) {
266
+ return this.data(pname).data;
267
+ } else {
268
+ this.data(pname).data = data;
269
+ }
270
+ return this;
271
+ },
272
+ /**
273
+ * Enables and disables combobox.
274
+ * @param {Boolean} b flag
275
+ * @returns {Object|Boolean} jQuery object or boolean desabled status.
276
+ */
277
+ disabled: function(b) {
278
+ var mode = this.data(pname).mode;
279
+ if (arguments.length == 0) {
280
+ if (mode == 'checkboxes') {
281
+ return this.hasClass(pname + cdisabled);
282
+ } else { // default mode
283
+ return this.children(cp + cdisplay).prop('disabled');
284
+ }
285
+ }
286
+ b = !!b;
287
+ this.children(cp + cdisplay).prop('disabled', b);
288
+ if (b) {
289
+ this.addClass(pname + cdisabled);
290
+ this.children(cp + cddback + ', ' + cp + cddarr).hide();
291
+ } else {
292
+ this.removeClass(pname + cdisabled);
293
+ this.children(cp + cddback + ', ' + cp + cddarr).show();
294
+ }
295
+ return this;
296
+ },
297
+ /**
298
+ * Sets the tabindex attribute for search input.
299
+ * @param index
300
+ * @returns {Number|Object}
301
+ */
302
+ tabindex: function(index) {
303
+ var $display = this.find(cp + cdisplay);
304
+ if (arguments.length == 0) {
305
+ return $display.attr('tabindex');
306
+ } else {
307
+ $display.attr('tabindex', index);
308
+ return this;
309
+ }
310
+ },
311
+ /**
312
+ * Resets options or see the options. Do not use this for changing data because merging is deep, so
313
+ * data may be merged instead of being replaced.
314
+ * For updating data use data method.
315
+ * @param {Object} options
316
+ * @returns {Object} jQuery object or options object
317
+ */
318
+ options: function(options) {
319
+ if (arguments.length == 0) {
320
+ return this.data(pname);
321
+ }
322
+ $.extend(true, this.data(pname), toCamelCase(options));
323
+ return this;
324
+ },
325
+ /**
326
+ * Combobox value setter and getter.
327
+ * @param {String|Array} v value
328
+ * @returns {Object|String|Array} jQuery object or string/array combobox current value.
329
+ * Value returns as string in the default mode and as an array of values where items were
330
+ * checked in checkboxes mode.
331
+ * If combobox is disabled then empty string is returned.
332
+ */ // TODO add the second parameter: flag if trigger changing the value (now it is triggering by default)
333
+ val: function(v) {
334
+ var opts = this.data(pname),
335
+ mode = opts.mode;
336
+ if (arguments.length == 0) { // get the value
337
+ if (mode == 'default') {
338
+ var value = this.find(cp + cvalue).val();
339
+ }
340
+ return mode == 'default' ?
341
+ (this.find(cp + cdisplay).is(':disabled') ? '' : value) :
342
+ (mode == 'checkboxes' ? getValues.call(this) : null);
343
+ } else { // set the value
344
+ if (mode == 'default') {
345
+ setValue.call(this, v);
346
+ } else if (mode == 'checkboxes') {
347
+ setValues.call(this, v);
348
+ }
349
+ }
350
+ return this;
351
+ },
352
+ open: function() {
353
+ slide.call(this.children(cp + clist), 'down');
354
+ return this;
355
+ },
356
+ close: function() {
357
+ slide.call(this.children(cp + clist), 'up');
358
+ return this;
359
+ },
360
+ /*
361
+ * Listeners.
362
+ * Call $('#combo').combobox('keyup', null, 'namespace');
363
+ * to trigger an event of specific namespace.
364
+ */
365
+ change: function(callback, namespace) {
366
+ return bindOrTrig.call(this, 'change', this.children(cp + cvalue), callback, namespace);
367
+ },
368
+ focus: function(callback, namespace) {
369
+ return bindOrTrig.call(this, 'focus', this.children(cp + cdisplay), callback, namespace);
370
+ },
371
+ blur: function(callback, namespace) {
372
+ return bindOrTrig.call(this, 'blur', this.children(cp + cdisplay), callback, namespace);
373
+ },
374
+ keyup: function(callback, namespace) {
375
+ return bindOrTrig.call(this, 'keyup', this.children(cp + cdisplay), callback, namespace);
376
+ },
377
+ keydown: function(callback, namespace) {
378
+ return bindOrTrig.call(this, 'keydown', this.children(cp + cdisplay), callback, namespace);
379
+ },
380
+ keypress: function(callback, namespace) {
381
+ return bindOrTrig.call(this, 'keypress', this.children(cp + cdisplay), callback, namespace);
382
+ },
383
+ click: function(callback, namespace) {
384
+ return bindOrTrig.call(this, 'click', this.children(cp + cdisplay), callback, namespace);
385
+ },
386
+ mousedown: function(callback, namespace) {
387
+ return bindOrTrig.call(this, 'mousedown', this.children(cp + cdisplay), callback, namespace);
388
+ },
389
+ clickDropdown: function(callback, namespace) {
390
+ return bindOrTrig.call(this, 'click', this.children(cp + cddarr), callback, namespace);
391
+ },
392
+ toSelect: function() {
393
+ var $select = this.children('select').insertAfter(this);
394
+ if (this.data(pname).reassignId) {
395
+ $select.attr('id', this.attr('id'));
396
+ }
397
+ this.remove();
398
+ return $select;
399
+ },
400
+ displayDropdown: function(b) {
401
+ if (arguments.length) {
402
+ if (!!b) {
403
+ this.children(cp + cddarr + ', ' + cp + cddback).show();
404
+ } else {
405
+ this.children(cp + cddarr + ', ' + cp + cddback).hide();
406
+ }
407
+ } else {
408
+ if (this.data(pname).showDropdown) {
409
+ this.children(cp + cddarr + ', ' + cp + cddback).show();
410
+ } else {
411
+ this.children(cp + cddarr + ', ' + cp + cddback).hide();
412
+ }
413
+ }
414
+ return this;
415
+ },
416
+ placeholder: function(text) {
417
+ var $input = this.children(cp + cdisplay);
418
+ if (!arguments.length) {
419
+ return $input.attr('placeholder');
420
+ } else {
421
+ $input.attr('placeholder', text);
422
+ return this;
423
+ }
424
+ }
425
+ };
426
+
427
+ function bindOrTrig(type, $element, callback, namespace) {
428
+ if (typeof callback != 'function') { // trigger
429
+ var action = type + (typeof callback == 'string' ? '.' + callback : (typeof namespace == 'string' ? '.' + namespace : ''));
430
+ $element.trigger(action);
431
+ } else { // bind
432
+ addAdditionalListener.call($element, type, callback, namespace);
433
+ }
434
+ return this;
435
+ }
436
+
437
+ function addAdditionalListener(type, callback, namespace) {
438
+ var action = type + (typeof namespace == 'string' ? '.' + namespace : '');
439
+ this.bind(action, callback);
440
+ }
441
+
442
+ function getValues() { // for checkbox mode
443
+ return JSON.parse(this.find(cp + cvalue).val() || '[]');
444
+ }
445
+
446
+ /**
447
+ * Executes after checking a checkbox.
448
+ * this refers to combobox.
449
+ */ // TODO remove duplicate code if possible
450
+ function updateValueInput() { // used for checkboxes mode only
451
+ var $paragraphs = $(this).find(cp + clist + ' p'),
452
+ $vInput = $(this).children(cp + cvalue),
453
+ arrV = [];
454
+ $paragraphs.each(function() {
455
+ var $p = $(this);
456
+ var $check = $p.find(':checkbox');
457
+ if ($check.prop('checked')) {
458
+ arrV.push($p.data('value'));
459
+ }
460
+ });
461
+ $(this).children('select').val(arrV);
462
+ $vInput.val(JSON.stringify(arrV));
463
+ }
464
+
465
+ function setValues(values) { // for checkboxes mode; this refers to combobox
466
+ var $paragraphs = $(this).find(cp + clist + ' p'),
467
+ $vInput = $(this).children(cp + cvalue),
468
+ arrV = [];
469
+ var $lastChecked;
470
+ for (var i = 0; i < $paragraphs.length; i++) {
471
+ var $p = $paragraphs.eq(i),
472
+ ind = values.indexOf($p.data('value'));
473
+ if (values.indexOf($p.data('value')) >= 0) {
474
+ $lastChecked = $p.find(':checkbox').prop('checked', true);
475
+ arrV.push(values[ind]);
476
+ } else {
477
+ $p.find(':checkbox').prop('checked', false);
478
+ }
479
+ }
480
+ $(this).children('select').val(values);
481
+ if ($lastChecked) {
482
+ $lastChecked.trigger(pname + '-chupdate', [true]);
483
+ $vInput.val(JSON.stringify(arrV));
484
+ }
485
+ }
486
+
487
+ function setValue(value) { // for default mode
488
+ var $t = $(this);
489
+ var O = this.data(pname);
490
+ var $select = $t.children('select'),
491
+ $valueInput = $t.children(cp + cvalue),
492
+ $display = $t.children(cp + cdisplay);
493
+ //find the option whose 'value' is (=) to the given value in the select element
494
+ var $selected = $select
495
+ .find('option')
496
+ .filter(function() {
497
+ return this.value == value;
498
+ });
499
+
500
+ $display.removeClass(pname + cinvalid).siblings(cp + cddback).removeClass(pname + cddback + cinvalid)
501
+ if (!$selected.length) { // no such value
502
+ $t.find(cp + clist + ' p').removeClass(pname + chovered);
503
+ $select.children().prop('selected', false);
504
+ if (!O.invalidAsValue) {
505
+ value = ''; // TODO make combobox return null instead of empty string (standard select behavior)
506
+ } else {
507
+ if (O.highlightInvalid || (O.invalidAsValue ? (O.highlightInvalid) : O.highlightInvalid === null)) {
508
+ $display.addClass(pname + cinvalid).siblings(cp + cddback)
509
+ .addClass(pname + cddback + cinvalid);
510
+ }
511
+ }
512
+ $valueInput.val(value);
513
+ $display.val(value);
514
+ return;
515
+ }
516
+ $t.find(cp + clist + ' p').eq($selected[0].index).addClass(pname + chovered).siblings().removeClass(pname + chovered);
517
+
518
+ $valueInput.val(value).data('changed', true);
519
+ $select.val(value).change();
520
+ }
521
+
522
+ /**
523
+ * Add all the combobox logic.
524
+ * @returns {undefined}
525
+ */
526
+
527
+ var blurTimer;
528
+
529
+ function addListeners() {
530
+ if (this.data('listenersAdded')) { // prevent duplicating listeners
531
+ return;
532
+ }
533
+ var $T = this,
534
+ O = $T.data(pname);
535
+
536
+ var typingTimer = null;
537
+ this.on('keyup', cp + cdisplay + ', ' + cp + cdiv, function(e) { // filter
538
+ // Ignore keys that can't alter input field value on their own
539
+ if ([38, //Up arrow
540
+ 40, //Down arrow
541
+ 13, //Enter
542
+ 27, //Escape
543
+ 9, //Tab
544
+ 37, //Left arrow
545
+ 39, //Right arrow
546
+ 17, //Ctrl
547
+ 18, //Alt
548
+ 16, //Shift
549
+ 20, //Caps lock
550
+ 33, //Page up
551
+ 34, //Page down
552
+ 35, //End
553
+ 36 //Home
554
+ ].indexOf(e.which) >= 0) {
555
+ return;
556
+ }
557
+
558
+ var doneTyping = function(e) {
559
+ // Some extra cases
560
+ if (!e.ctrlKey && !e.shiftKey && e.which == 45) return; //Insert without modifier
561
+ if (e.ctrlKey && e.which == 65) return; //Ctrl+A; imperfect because sometimes we release the A *after* the Ctrl
562
+
563
+ var fullMatch = O.fullMatch,
564
+ highlight = O.highlight;
565
+ if (fullMatch) {
566
+ highlight = highlight !== false;
567
+ } else {
568
+ highlight = !!highlight;
569
+ }
570
+ var $t = $(this),
571
+ search = this.value.trim();
572
+ if (O.filterIgnoreCase) {
573
+ search = search.toLowerCase();
574
+ }
575
+ if (O.filterIgnoreAccents && String.prototype.latinize) {
576
+ search = search.latinize();
577
+ }
578
+ var $div = $t.closest(cp).children(cp + clist);
579
+ slide.call($div, 'down', true);
580
+ var $options = $t.closest(cp).find('select option');
581
+ $(cp + ' ' + cp + clist).each(function() {
582
+ if ($div[0] != this) {
583
+ slide.call($(this), 'up');
584
+ }
585
+ });
586
+ if (!search) {
587
+ $div.children('p').show().each(function() {
588
+ $(cp + '-marker', this).contents().unwrap(); // remove selection
589
+ });
590
+ return;
591
+ }
592
+ var hideSelector = O.hideSeparatorsOnSearch ? 'p' : 'p:not(' + cp + csep + ', ' + cp + cpheader + ')';
593
+ $div.children(hideSelector).hide();
594
+ $options.each(function() {
595
+ var text = $(this).text().trim();
596
+ if (O.filterIgnoreCase) {
597
+ text = text.toLowerCase();
598
+ }
599
+ if (O.filterIgnoreAccents && String.prototype.latinize) {
600
+ text = text.latinize();
601
+ }
602
+ if (fullMatch ? text.indexOf(search) >= 0 : text.indexOf(search) == 0) {
603
+ // check index and show corresponding paragraph
604
+ var regexFlags = O.filterIgnoreCase ? 'i' : '';
605
+ var re = new RegExp("(" + search.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1") + ")", fullMatch ? regexFlags + 'g' : regexFlags);
606
+ var $ps = $div.children('p:eq(' + $options.index(this) + '):not(' + cp + csep + ', ' + cp + cpheader + ')').show();
607
+ if (highlight) {
608
+ $ps.each(function() {
609
+ $(cp + '-marker', this).contents().unwrap(); // remove previous selection
610
+ var mainSpan = $(cp + cmainspan, this)[0];
611
+ mainSpan.innerHTML = mainSpan.innerHTML.replace(re, '<span class="' + pname + '-marker">$1</span>');
612
+ });
613
+ }
614
+ }
615
+ });
616
+ };
617
+
618
+ var t = this;
619
+ var delay = O.filterDelay;
620
+ if (!delay) {
621
+ doneTyping.call(t, e);
622
+ } else {
623
+ clearTimeout(typingTimer);
624
+ typingTimer = setTimeout(function() {
625
+ doneTyping.call(t, e);
626
+ }, delay);
627
+ }
628
+ });
629
+ this.on('keydown', cp + cdisplay, function(e) {
630
+ if ([38, 40, 13, 27, 9].indexOf(e.which) >= 0) {
631
+ if (e.which != 9) {
632
+ e.preventDefault();
633
+ }
634
+ var $combobox = $(this).closest(cp);
635
+ var $div = $combobox.children(cp + clist);
636
+ var $hovered = $(cp + chovered, $div[0]),
637
+ $curr, offset;
638
+ var $first = $('p:first', $div[0]);
639
+ var cycle = O.loopScrolling;
640
+ var notHeaderSelector = ':not(' + cp + csep + '):not(' + cp + cpheader + ')'; // don't put both classes in single parenthesis for old jQuery versions
641
+ } else {
642
+ return;
643
+ }
644
+ var fillOnArrow = O.mode == 'default' ? O.fillOnArrowPress : false; // always false for checkboxes mode
645
+ if ($div.is(':animated')) {
646
+ return; // keydown event is only for arrows, enter and escape
647
+ }
648
+ var v = this.value.trim();
649
+ v = (O.filterIgnoreCase) ? v.toLowerCase() : v;
650
+ var scrollTop = $div.scrollTop();
651
+ if (e.which == 40) { // arrdown
652
+ if ($div.is(':hidden')) {
653
+ slide.call($div, 'down');
654
+ return;
655
+ }
656
+ if ($hovered.length == 0) {
657
+ if ($first.is(':visible' + notHeaderSelector)) {
658
+ $curr = $first.addClass(pname + chovered);
659
+ } else {
660
+ $curr = $first.nextAll(':visible' + notHeaderSelector).first().addClass(pname + chovered);
661
+ }
662
+ } else {
663
+ if (!cycle) {
664
+ if (!$hovered.nextAll(':visible' + notHeaderSelector).first().length) {
665
+ return;
666
+ }
667
+ }
668
+ $curr = $hovered.removeClass(pname + chovered).nextAll(':visible' + notHeaderSelector).first().addClass(pname + chovered);
669
+ if ($curr.length == 0) {
670
+ if ($first.is(':visible')) {
671
+ $curr = $first.addClass(pname + chovered);
672
+ } else {
673
+ $curr = $first.nextAll(':visible' + notHeaderSelector).first().addClass(pname + chovered);
674
+ }
675
+ }
676
+ if ($curr.length == 0) {
677
+ $curr = $first;
678
+ }
679
+ offset = $curr.position().top - $div.position().top;
680
+ var currHeight = $curr.outerHeight();
681
+ if (offset + currHeight * 6 > $div.height()) { // keep 4 elements ahead
682
+ if ((offset + currHeight * 6) - $div.height() > currHeight * 1.5) { // $curr is under the visible bottom border
683
+ $div.scrollTop(scrollTop + offset);
684
+ } else { // no fix required
685
+ $div.scrollTop(scrollTop + currHeight); // incremental scrolltop
686
+ }
687
+ } else if (offset < 0) {
688
+ $div.scrollTop(scrollTop - -offset);
689
+ }
690
+ }
691
+ if (fillOnArrow) {
692
+ this.value = $curr.find(cp + cmainspan).text();
693
+ $combobox.children(cp + cdisplay).data('fillonarrow', true);
694
+ }
695
+ } else if (e.which == 38) { // arrup
696
+ if ($div.is(':visible')) {
697
+ if (!cycle && !$hovered.prevAll(':visible' + notHeaderSelector).first().length) {
698
+ return;
699
+ }
700
+ $curr = $hovered.removeClass(pname + chovered).prevAll(':visible' + notHeaderSelector).first().addClass(pname + chovered);
701
+ if ($curr.length == 0) {
702
+ $curr = $('p:visible' + notHeaderSelector + ':last', $div[0]).addClass(pname + chovered);
703
+ }
704
+ offset = $curr.position().top - $div.position().top;
705
+ currHeight = $curr.outerHeight();
706
+ if (offset < currHeight * 3) {
707
+ $div.scrollTop(scrollTop - -offset - currHeight * 3);
708
+ } else if (offset > $div.height() - currHeight * 3) {
709
+ $div.scrollTop(scrollTop + offset - currHeight * 3); // to the last (was $div[0].scrollHeight)
710
+ }
711
+ if (fillOnArrow) {
712
+ this.value = $curr.find(cp + cmainspan).text();
713
+ $combobox.children(cp + cdisplay).data('fillonarrow', true);
714
+ }
715
+ }
716
+ } else if (e.which == 13) { // enter
717
+ if (O.fillOnBlur) {
718
+ getFirstP($div).click();
719
+ return;
720
+ }
721
+ $div.children(cp + chovered).click();
722
+ if (O.mode == 'default') {
723
+ slide.call($div, 'up');
724
+ }
725
+ } else if (e.which == 27) { // escape
726
+ var $t = O.blurOnEscape ? $(this).blur() : $(this);
727
+ // If list is down, escape slides it up and doesn't propagate outward
728
+ if ($div.is(':visible')) {
729
+ slide.call($div, 'up');
730
+ e.stopPropagation();
731
+ }
732
+ } else if (e.which == 9) { // tab
733
+ if (O.fillOnTab) {
734
+ if (v) {
735
+ // Used to pick the first visible item in the dropdown
736
+ // Now pick the selected item (if any)
737
+ var $p = $div.children(cp + chovered);
738
+ if ($p.length) {
739
+ // e.preventDefault(); why not to go further?
740
+ $p.click();
741
+ }
742
+ }
743
+ }
744
+ }
745
+ });
746
+ this.on('change', 'select', function(e, checkboxesMode) { // someone triggered combobox select change
747
+ var $combo = $(this).closest(cp);
748
+ var dtext = $('option:selected', this).text();
749
+ $combo.children(cp + cdisplay).val(dtext).data('value', dtext);
750
+ var $valueInput = $combo.children(cp + cvalue);
751
+ if ($valueInput.data('changed')) {
752
+ $valueInput.data('changed', false);
753
+ return;
754
+ }
755
+ if (checkboxesMode) { // no slideup for checkboxes mode
756
+ updateValueInput.call($combo);
757
+ $valueInput.change();
758
+ return;
759
+ }
760
+ $valueInput.change();
761
+ slide.call($combo.children(cp + clist), 'up'); // can be triggered at the page load
762
+ });
763
+ this.on(pname + '-chupdate', cp + clist + ' p :checkbox', function(e, forRefresh) {
764
+ if (forRefresh) {
765
+ e.stopPropagation();
766
+ checkboxesModePClick.call($(this).parent(), e, true);
767
+ }
768
+ });
769
+ this.on('click', cp + clist + ' p', function(e) { // value selected by clicking
770
+ clearTimeout(blurTimer);
771
+ e.stopPropagation();
772
+ if ($(this).is(cp + csep + ', ' + cp + cpheader)) {
773
+ return;
774
+ }
775
+ $T.children(cp + cinvalid).removeClass(pname + cinvalid); // 100% it is not invalid now
776
+ $T.children(cp + cddback).removeClass(pname + cddback + cinvalid);
777
+ var $t = $(this),
778
+ $div = $t.parent(),
779
+ $ps = $div.children();
780
+ var index = $ps.index(this);
781
+ if ($T.data(pname).mode == 'checkboxes') {
782
+ checkboxesModePClick.call(this, e); // process checking
783
+ return;
784
+ }
785
+ var $select = $div.closest(cp).children('select');
786
+ $select.children('option').eq(index).prop('selected', true);
787
+ $select.siblings(cp + cvalue).val($select.val());
788
+ $select.change();
789
+ slide.call($t.parent(), 'up');
790
+ $t.addClass(pname + chovered).siblings().removeClass(pname + chovered);
791
+ });
792
+ this.on('blur', cp + cdisplay, function(e) {
793
+ // Need to do some stuff only when user moves off the scombobox.
794
+
795
+ // Try to do nothing in this handler if losing focus to another part of this
796
+ // combobox (e.g. the down/up button, or the list itself).
797
+ // IE needs this technique in addition to the timer one (see below) because
798
+ // clicking on the dropped-down div's scroller (if present) gives a blur
799
+ // but no suitable subsequent event with which to cancel the timer.
800
+ var $t = $(this);
801
+ var rt = $(e.relatedTarget).closest(cp);
802
+ if (rt.length > 0 && rt[0] === $t.closest(cp)[0]) {
803
+ return;
804
+ }
805
+
806
+ // The relatedTarget technique doesn't work on Chrome or on Firefox.
807
+ // So we start a 200ms timer when display element loses focus. In click
808
+ // handlers of control's other elements clearTimeout cancels the timer.
809
+ // If the timer isn't cancelled it will fire and do the necessary slide up.
810
+ // We can't defer all the blur processing with this timer as doing so would
811
+ // mean that a click event on a submit button could get an outdated value
812
+ // from the scombobox, because the click would precede the timer event.
813
+ //
814
+ // Note that the timer's function's bind() method is used to supply it with the correct 'this'
815
+ blurTimer = setTimeout(
816
+ function() {
817
+ var $t = $(this),
818
+ O = $T.data(pname);
819
+ if (this === document.activeElement) {
820
+ // Suppress autoexpand on next focus if this blur was actually the entire window losing focus
821
+ // rather than this element losing focus to another element on the same window
822
+ $t.data('silentfocus', true);
823
+ }
824
+ $t.data('fillonarrow', false); // Prevent the slide-up from resetting value
825
+ slide.call($t.closest(cp).children(cp + clist), 'up'); // Make sure the list closes when we're sure we've left the control
826
+ }.bind(this), 200
827
+ );
828
+
829
+ //Is this necessary here? Seems to cause issues when on Chrome (cannot select list items correctly.
830
+ //The usefulness of fillOnBlur is debated, see https://github.com/ivkremer/jquery-simple-combobox/issues/25
831
+ //Either remove it entirely, or move it into the setTimeout function above.
832
+ /*
833
+ if (O.fillOnBlur && !O.invalidAsValue) {
834
+ getFirstP($t.parent().children(cp + clist)).click();
835
+ return;
836
+ }
837
+ */
838
+
839
+ var vOriginal = $t.val().trim();
840
+ var $valueInput = $t.siblings(cp + cvalue);
841
+ var previousV = $valueInput.val();
842
+ if (!vOriginal) { // if combo was emptied then set its value to '':
843
+ $valueInput.val('');
844
+ } else {
845
+ var value;
846
+ $t.siblings('select').find('option').each(function() {
847
+ if (O.filterIgnoreCase) {
848
+ if (vOriginal.toLowerCase() == $(this).text().trim().toLowerCase()) {
849
+ value = this.value;
850
+ }
851
+ } else {
852
+ if (vOriginal == $(this).text().trim()) {
853
+ value = this.value;
854
+ }
855
+ }
856
+ });
857
+ if (!value) { // value not found (invalid)
858
+ $valueInput.val(O.invalidAsValue ? vOriginal : '');
859
+ } else {
860
+ $valueInput.val(value);
861
+ }
862
+ }
863
+ if (previousV !== $valueInput.val()) {
864
+ $valueInput.change().data('changed', true);
865
+ }
866
+ });
867
+ this.on('focus', cp + cdisplay, function() {
868
+
869
+ // Check for indicator that focus shouldn't cause expansion
870
+ if ($(this).data('silentfocus')) {
871
+ $(this).data('silentfocus', false);
872
+ return;
873
+ }
874
+ if (!this.value.trim()) { // focusing in empty field
875
+ // should trigger full dropdown:
876
+ if (($T.data(pname).expandOnFocus) || ($(this).data('expandfocus'))) {
877
+ $(this).keyup();
878
+ }
879
+ } else { // input.display is not empty
880
+ if (($T.data(pname).expandOnFocusWithValue) || ($(this).data('expandfocus'))) {
881
+ if ($T[pname]('val')) { // if value is valid
882
+ var $listDiv = $T.children(cp + clist);
883
+ $listDiv.children().show();
884
+ slide.call($listDiv, 'down');
885
+ } else {
886
+ $(this).keyup(); // else start filtering
887
+ }
888
+ }
889
+ }
890
+ $(this).data('expandfocus', false);
891
+ });
892
+ this.on('click', cp + cdisplay + '-div', function() {
893
+ if ($T.data(pname).disabled) {
894
+ return;
895
+ }
896
+ slide.call($(this).siblings(cp + clist), 'down');
897
+ });
898
+ this.on('click', cp + cdisplay, function(e) {
899
+ var t = $(this).closest(cp)[0];
900
+ $(cp).each(function() { // close all other comboboxes
901
+ if (this != t) {
902
+ $(this)[pname]('close');
903
+ }
904
+ });
905
+ e.stopPropagation();
906
+ });
907
+ this.on('click', cp + cddarr, function(e) {
908
+ clearTimeout(blurTimer);
909
+ var $t = $(this),
910
+ $combo = $t.closest(cp);
911
+ var $div = $combo.children(cp + clist);
912
+ if ($div.is(':visible')) {
913
+ slide.call($div, 'up');
914
+ $combo.children(cp + cdisplay).data('silentfocus', true).focus();
915
+ } else {
916
+ $combo.children(cp + cdisplay).data('expandfocus', true).focus();
917
+ }
918
+ });
919
+ this.on('click', cp + cdiremove, function(e) {
920
+ clearTimeout(blurTimer);
921
+ e.stopPropagation();
922
+ var $t = $(this);
923
+ var $item = $t.parent(),
924
+ $div = $T.children(cp + clist);
925
+ $div.children('p').eq($t.data('index')).find(':checkbox').prop('checked', false);
926
+ $item.fadeOut(O.animation.duration);
927
+ $t.closest(cp).children('select').trigger('change', [true]);
928
+ });
929
+ // scroll listener is for ajax loading
930
+ if (O.autoLoad != $.noop) {
931
+ $(cp + clist, this).scroll(function() {
932
+ var $t = $(this),
933
+ $select = $T.children('select');
934
+ var currentScrollTop = $t.scrollTop();
935
+ var overhead = 50;
936
+ if (currentScrollTop > $t.data('scrollTop')) { // scrolling down
937
+ if (this.scrollHeight - currentScrollTop - overhead < $t.height()) {
938
+ if (!$T.data('pending')) {
939
+ $T.data('pending', true);
940
+ O.autoLoad.call($T, $select.find('option[value]:last').val(), 'bottom');
941
+ }
942
+ }
943
+ } else { // scrolling up
944
+ if (currentScrollTop < $t.height() / 2) {
945
+ if (!$T.data('pending')) {
946
+ $T.data('pending', true);
947
+ O.autoLoad.call($T, $select.find('option[value]:first').val(), 'top');
948
+ }
949
+ }
950
+ }
951
+ $t.data('scrollTop', currentScrollTop);
952
+ }).data('scrollTop', 0);
953
+ }
954
+
955
+
956
+ $(document).bind('click.' + pname, { thisIs: this }, function(e) {
957
+ slide.call($(e.data.thisIs).children(cp + clist), 'up');
958
+ });
959
+
960
+ this.data('listenersAdded', true);
961
+ }
962
+
963
+ /**
964
+ * Converts given data to final form in the most convenient way.
965
+ * @param {Array} data data given as options.data param
966
+ * @returns {Array|Boolean} array of data objects or false if no data were given
967
+ */
968
+ function normalizeData(data) {
969
+ if (typeof data == 'string') { // json given
970
+ data = $.parseJSON(data);
971
+ if (data == null) { // null == empty array
972
+ return [];
973
+ }
974
+ }
975
+ if (!data) { // all falsy except empty string
976
+ return false;
977
+ }
978
+ if (!(data instanceof Array)) { // object (probably) was given, convert it to array
979
+ if (typeof data != 'object') {
980
+ return false;
981
+ }
982
+ if (typeof data.length == 'undefined') {
983
+ data.length = Object.keys(data).length;
984
+ }
985
+ data = [].slice.call(data);
986
+ }
987
+ return data; // array was given
988
+ }
989
+
990
+ function purifyData(data) {
991
+ for (var i = 0; i < data.length; i++) {
992
+ if ((!data[i].value || !data[i].text) && !(data[i].hasOwnProperty('separator'))) {
993
+ data.splice(i, 1);
994
+ }
995
+ }
996
+ }
997
+
998
+ function purifyOptions($options) {
999
+ for (var i = 0; i < $options.length; i++) {
1000
+ if (!$options[i].value && !$($options[i]).hasClass(pname + csep) && $options[i].tagName.toLowerCase() != 'optgroup') { // if no value,
1001
+ // but if it is a separator, then it is no matter if there is a not empty value
1002
+ // if this is an optgroup tag, then it will be used as a separator
1003
+ $($options[i]).remove();
1004
+ }
1005
+ }
1006
+ }
1007
+
1008
+ function sortF(a, b) {
1009
+ var aT = a.text.trim().toLowerCase(),
1010
+ bT = b.text.trim().toLowerCase();
1011
+ return aT > bT ? 1 : aT == bT ? 0 : -1;
1012
+ }
1013
+
1014
+ function removeDups(a) {
1015
+ for (var i = 0; i < a.length; i++) {
1016
+ for (var j = i + 1; j < a.length; j++) {
1017
+ if (!a[i] || !a[j])
1018
+ continue;
1019
+ if (a[i].value == a[j].value)
1020
+ a.splice(i, 1);
1021
+ }
1022
+ }
1023
+ }
1024
+
1025
+ function removeDupsjQ(a) {
1026
+ for (var i = 0; i < a.length; i++) {
1027
+ for (var j = i + 1; j < a.length; j++) {
1028
+ if (!a[i] || !a[j])
1029
+ continue;
1030
+ if (a[i].value == a[j].value && a[i].tagName.toLowerCase() != 'optgroup') {
1031
+ $(a[i]).remove();
1032
+ }
1033
+ }
1034
+ }
1035
+ }
1036
+
1037
+ /**
1038
+ * `this` refers to combobox
1039
+ */
1040
+ function checkForInvalid() {
1041
+ var $display = this.children(cp + cdisplay),
1042
+ $select = this.children('select'),
1043
+ O = this.data(pname);
1044
+ var value, v = $display.val().trim();
1045
+ v = (O.filterIgnoreCase) ? v.toLowerCase() : v;
1046
+ // check if such value exists in options
1047
+ $select.find('option').each(function() {
1048
+ var candidate = $(this).text().trim();
1049
+ candidate = (O.filterIgnoreCase) ? candidate.toLowerCase() : candidate;
1050
+ if (candidate == v) {
1051
+ value = this.value;
1052
+ }
1053
+ });
1054
+ var invalid = (!value && v);
1055
+ if (invalid) {
1056
+ if (O.forbidInvalid) {
1057
+ $display.closest(cp).find(cp + cdisplay).val('').data('value', '');
1058
+ } else {
1059
+ // if highlightInvalid is enabled directly (default is null)
1060
+ // or invalidAsValue is on and highlightInvalid is not its default:
1061
+ // TODO refactor to make a more readable code:
1062
+ if (O.highlightInvalid || (O.invalidAsValue ? (O.highlightInvalid) : O.highlightInvalid === null)) {
1063
+ $display.addClass(pname + cinvalid).siblings(cp + cddback)
1064
+ .addClass(pname + cddback + cinvalid);
1065
+ }
1066
+ }
1067
+ if (!O.invalidAsValue) { // TODO check if this code affects anything
1068
+ $display.siblings('select, ' + cp + cvalue).val('');
1069
+ }
1070
+ } else {
1071
+ $display.removeClass(pname + cinvalid).siblings(cp + cddback).removeClass(pname + cddback + cinvalid);
1072
+ }
1073
+ }
1074
+
1075
+ /**
1076
+ * Slides the div with a list. `this` refers to the list
1077
+ * @param dir 'up' = collapse, 'down' = expand.
1078
+ * @param backspace to fix backspace bug
1079
+ */ // TODO rename and comment backspace argument
1080
+ function slide(dir, backspace) {
1081
+ if (this.is(':animated') || !this.length) {
1082
+ return;
1083
+ }
1084
+ if (dir == 'up' && this.is(':hidden') && this.length == 1) {
1085
+ return; // todo put a comment: why? (one reason is probably optimization, but what is this.length == 1 for?)
1086
+ }
1087
+ var options = this.parent().data(pname).animation;
1088
+ if (!$.easing[options.easing]) {
1089
+ console.warn('no such easing: ' + options.easing);
1090
+ options.easing = 'swing';
1091
+ }
1092
+ var $combobox = this.parent(),
1093
+ O = $combobox.data(pname);
1094
+ if (dir == 'up') {
1095
+ O.beforeClose.call($combobox);
1096
+ options.complete = function() {
1097
+ if (O.mode != 'checkboxes') {
1098
+ checkForInvalid.call($combobox);
1099
+ }
1100
+ O.afterClose.call($combobox);
1101
+ };
1102
+ this.slideUp(options).data('p-clicked-index', -1);
1103
+ $combobox.children(cp + cddarr).removeClass(pname + cddarr + '-up');
1104
+ } else {
1105
+ O.beforeOpen.call($combobox);
1106
+ options.complete = function() { O.afterOpen.call($combobox) };
1107
+ this.slideDown(options);
1108
+ $combobox.children(cp + cddarr).addClass(pname + cddarr + '-up');
1109
+
1110
+ // Every edit keystroke will call a slide down; use this opportunity to reset the list's display characteristics fully.
1111
+ $combobox.find(cp + chovered).removeClass(pname + chovered); // remove previous selection
1112
+ $(cp + '-marker', $combobox).contents().unwrap(); // remove previous highlight
1113
+
1114
+ // Reveal everything whenever we slide down, so that user gets to see all the options.
1115
+ // If the slide down was triggered by entry of a character, filtering will immediately reduce the list
1116
+ // to matching items. If the slide down was by clicking the down-button, or entry of cursor-down,
1117
+ // all entries will remain displayed.
1118
+ $combobox.children(cp + clist).children('p').show();
1119
+ }
1120
+ var $display = $combobox.children(cp + cdisplay); // code for fillOnArrowPress feature
1121
+ $display.each(function() {
1122
+ var $t = $(this);
1123
+ if ($t.data('fillonarrow') && !backspace) { // fix backspace bug
1124
+ $t.data('fillonarrow', false).val($t.data('value'));
1125
+ }
1126
+
1127
+ // Highlight first full match when dropping down
1128
+ if (dir == 'down') {
1129
+ var search = this.value.trim();
1130
+ if (O.filterIgnoreCase) {
1131
+ search = search.toLowerCase();
1132
+ }
1133
+ var $selopts = $combobox.find('select option');
1134
+ $selopts.each(function() {
1135
+ var text = $(this).text().trim();
1136
+ if (O.filterIgnoreCase) {
1137
+ text = text.toLowerCase();
1138
+ }
1139
+ if (text == search) {
1140
+ $combobox.children(cp + clist).children('p:eq(' + $selopts.index(this) + '):not(' + cp + csep + ', ' + cp + cpheader + ')').first().addClass(pname + chovered);
1141
+ return false;
1142
+ }
1143
+ });
1144
+ }
1145
+ });
1146
+ }
1147
+
1148
+ function checkboxesModePClick(e, forRefresh) { // this refers to paragraph dom element
1149
+ var $t = $(this),
1150
+ $combo = $t.closest(cp),
1151
+ $div = $t.parent(),
1152
+ $ps = $div.children('p'),
1153
+ index = $ps.index(this),
1154
+ duration = durations($div.parent().data(pname).animation.duration);
1155
+ if (!forRefresh) {
1156
+ var $chbox = $t.find(':checkbox');
1157
+ // don't toggle prop('checked') if checkbox itself was clicked.
1158
+ if (!$(e.target).is(':checkbox')) {
1159
+ $chbox.prop('checked', !$chbox.prop('checked')); // avoid clicking, change prop instead
1160
+ }
1161
+ var choice = $chbox.prop('checked');
1162
+ if (e.shiftKey) { // mark between last click and current
1163
+ if ($div.data('p-clicked-index') >= 0) { // not for the first time
1164
+ var f = $div.data('p-clicked-index');
1165
+ var from = f < index ? f : index,
1166
+ to = f < index ? index : f;
1167
+ for (var i = from; i <= to; i++) {
1168
+ $($ps[i]).find(':checkbox').prop('checked', choice);
1169
+ }
1170
+ }
1171
+ }
1172
+ }
1173
+ var $dispDivHolder = $combo.find(cp + cdholder).prepend('<span />');
1174
+ $combo.find(cp + cdholder).fadeOut(duration / 5, function() {
1175
+ $dispDivHolder.empty().show();
1176
+ // get all selected properties
1177
+ $ps.each(function(i) {
1178
+ var $t = $(this);
1179
+ if ($t.find(':checkbox').prop('checked')) {
1180
+ $dispDivHolder.append(
1181
+ $('<div />').addClass(pname + cditem)
1182
+ .append($('<div />').addClass(pname + cditem + '-text').text($t.find(cp + cmainspan).text()))
1183
+ .append($('<div />').addClass(pname + cdiremove).text('×').data('index', i)).fadeIn(duration * 1.5)
1184
+ .attr('title', $t.attr('title'))
1185
+ );
1186
+ }
1187
+ });
1188
+ $dispDivHolder.append('<div style="clear: both" />');
1189
+ });
1190
+ $div.data('p-clicked-index', index);
1191
+ $t.closest(cp).children('select').trigger('change', [true]); // true for do not slideup the items div
1192
+ }
1193
+
1194
+ /**
1195
+ * @param items
1196
+ * @param prepend flag if prepend instead of appending
1197
+ */
1198
+ function renderItems(items, prepend) {
1199
+ var settings = this.data(pname);
1200
+ var $select = this.find('select'),
1201
+ $div = this.find(cp + clist);
1202
+ for (var i = 0; i < items.length; i++) {
1203
+ if (items[i].hasOwnProperty('separator')) { // if separator given then
1204
+ if (items[i].hasOwnProperty('header')) { // if header text also given then add only header
1205
+ $p = $('<p class="' + pname + cpheader + '" />').text(items[i].header);
1206
+ } else { // else add separator itself
1207
+ var $p = $('<p class="' + pname + csep + '" />');
1208
+ }
1209
+ var $option = $('<option />');
1210
+ } else { // regular item
1211
+ $option = $('<option />').val(items[i].value).text(items[i].text).prop('selected', !!items[i].selected);
1212
+ $p = settings.pFillFunc.call(this, items[i], settings);
1213
+ if (settings.mode == 'checkboxes') {
1214
+ $p.prepend('<input type="checkbox" />');
1215
+ }
1216
+ }
1217
+ $p.data('value', items[i].value);
1218
+ if (prepend) {
1219
+ $select.prepend($option);
1220
+ $div.prepend($p);
1221
+ } else {
1222
+ $select.append($option);
1223
+ $div.append($p);
1224
+ }
1225
+ }
1226
+ }
1227
+
1228
+ function getFirstP($clist) {
1229
+ var $closestP = $clist.children(cp + chovered + ':visible');
1230
+ if ($closestP.length == 0) {
1231
+ $closestP = $clist.children(':visible:first');
1232
+ }
1233
+ return $closestP;
1234
+ }
1235
+
1236
+ function toCamelCase(o) {
1237
+ if (o == null) {
1238
+ return null;
1239
+ }
1240
+ var keys = Object.keys(o);
1241
+ for (var k = 0; k < keys.length; k++) {
1242
+ var key = keys[k].replace(/-([a-z])/g, function(g) {
1243
+ return g[1].toUpperCase() });
1244
+ if (keys[k] != key) { // hyphened property
1245
+ o[key] = o[keys[k]];
1246
+ delete o[keys[k]];
1247
+ }
1248
+ if (typeof o[key] == 'object' && key != 'data') {
1249
+ toCamelCase(o[key]);
1250
+ }
1251
+ }
1252
+ return o;
1253
+ }
1254
+
1255
+ /**
1256
+ * The core.
1257
+ * @param {Object|String} actOrOpts action (string) or options (object)
1258
+ * @returns {Object|void} jQuery object on success. Throws error on undefined method.
1259
+ */
1260
+ $.fn[pname] = function(actOrOpts) {
1261
+ if (typeof actOrOpts == 'string') {
1262
+ if (!this.length) { // method called on empty collection
1263
+ $.error('Calling ' + pname + '.' + actOrOpts + '() method on empty collection');
1264
+ }
1265
+ if (this.data(pname + '-init') == null) { // it can be legally false, but not undefined
1266
+ $.error('Calling ' + pname + '.' + actOrOpts + '() method prior to initialization');
1267
+ }
1268
+ var method = methods[actOrOpts];
1269
+ if (!method) {
1270
+ $.error('No such method: ' + actOrOpts + ' in jQuery.' + pname + '()');
1271
+ }
1272
+ } else if (['object', 'undefined'].indexOf(typeof actOrOpts) >= 0) {
1273
+ var options = $.extend(true, {}, $.fn[pname].defaults, toCamelCase(actOrOpts));
1274
+ } else {
1275
+ $.error('Incorrect usage');
1276
+ return this;
1277
+ }
1278
+ if (method) {
1279
+ return method.apply(this, Array.prototype.slice.call(arguments, 1));
1280
+ }
1281
+ return this.each(function() {
1282
+ var $t = $(this);
1283
+ if ($t.parent().hasClass(pname)) {
1284
+ return; // already initialized
1285
+ }
1286
+ if ($t.is('select')) {
1287
+ $t.wrap('<div />');
1288
+ if (options.reassignId) {
1289
+ $t.parent().attr('id', $t.attr('id'));
1290
+ }
1291
+ $t = $t.parent();
1292
+ }
1293
+ $t.data(pname, $.extend(true, {}, options)); // cloning object is required for cases like:
1294
+ // $('multiple targets selector').combobox(settings)
1295
+ // $('one of a bunch').combobox('options', propertiesToChange)
1296
+ // If the options object is not cloned above,
1297
+ // then changing properties will affect every target in the original set.
1298
+ methods.init.apply($t);
1299
+ });
1300
+ };
1301
+
1302
+ $.fn[pname].defaults = {
1303
+ /**
1304
+ * If no data given combobox is filled relying on $('select option') list.
1305
+ * By default (see pMarkup and pFillFunc) the data is an array of objects:
1306
+ * {value: '', text: '', additional: '', selected: true/false, anyCustomOption: customValue}
1307
+ * You can also provide json or object with enumerated properties:
1308
+ * {0: {...}, 1: {...}, ...}
1309
+ */
1310
+ data: null,
1311
+ /**
1312
+ * Whether combobox is empty by default (true) or has an original select value (usually it the first value,
1313
+ * but can be changed by added a `selected` prop).
1314
+ */
1315
+ empty: false,
1316
+ /**
1317
+ * Whether set required attribute.
1318
+ */
1319
+ required: false,
1320
+ /**
1321
+ * Whether set combobox disabled.
1322
+ */
1323
+ disabled: false,
1324
+ /**
1325
+ * Whether to sort options alphabetically or not
1326
+ */
1327
+ sort: true,
1328
+ /**
1329
+ * false to sort descending
1330
+ */
1331
+ sortAsc: true,
1332
+ /**
1333
+ * Whether to remove duplicates (regarding to values only).
1334
+ * Not removing duplicated may cause an error, so be careful
1335
+ */
1336
+ removeDuplicates: true,
1337
+ /**
1338
+ * Whether to match in any part of the option text or only start from the beginning of the text
1339
+ */
1340
+ fullMatch: false,
1341
+ /**
1342
+ * By default highlighting is turned on when fullMatch is turned on.
1343
+ * Set it strictly to false to disable it anyway or to any truthy value to set it always enabled
1344
+ */
1345
+ highlight: null,
1346
+ /**
1347
+ * Whether to ignore case while filtering.
1348
+ */
1349
+ filterIgnoreCase: true,
1350
+ /**
1351
+ * Whether to convert a needle and a haystack like 'Cajicá' or 'Hősök' to 'Cajica' and 'Hosok'.
1352
+ */
1353
+ filterIgnoreAccents: false,
1354
+ /**
1355
+ * Whether to debounce search function, falsy value for no debounce.
1356
+ */
1357
+ filterDelay: 0,
1358
+ /**
1359
+ * Hide separators when typing something in a combo.
1360
+ */
1361
+ hideSeparatorsOnSearch: false,
1362
+ /**
1363
+ * When false options list does not drop down on focus (applies on an empty combobox).
1364
+ * In this case you have to click on arrow to expand the list or start typing.
1365
+ */
1366
+ expandOnFocus: true,
1367
+ /**
1368
+ * When false options list does not drop down on focus (applies on a filled combobox).
1369
+ */
1370
+ expandOnFocusWithValue: true,
1371
+ /**
1372
+ * Set tabindex
1373
+ */
1374
+ tabindex: null,
1375
+ /**
1376
+ * When true, invalid values are forbidden what means combobox search input empties on blur in case the value
1377
+ * was not chosen and search field contained wrong text.
1378
+ * When false, incorrect filled combobox search field will has invalid css class.
1379
+ */
1380
+ forbidInvalid: false,
1381
+ /**
1382
+ * When true, then value from visible input will be a value returned by `$(combo).scombobox('val');`
1383
+ */
1384
+ invalidAsValue: false,
1385
+ /**
1386
+ * Whether to mark a combobox with invalid value with red or not. By default it is turned on.
1387
+ * When `invalidAsValue` option is set to true, `highlightInvalid` is considered false by default.
1388
+ * If you want to enabled or disable it regardless to `invalidAsValue`, set it to a any truthy value or not null
1389
+ * falsy value correspondingly.
1390
+ */
1391
+ highlightInvalid: null,
1392
+ /**
1393
+ * If true id from select will be reassigned to the created combobox div when query target was select, like $('select').combobox()
1394
+ */
1395
+ reassignId: true,
1396
+ /**
1397
+ * Combobox mode 'default' means it is looking like select box with input for searching.
1398
+ * mode 'checkboxes' means every option has a checkbox. In checkboxes mode the value of
1399
+ * combobox is an array of values which were checked.
1400
+ */
1401
+ mode: 'default',
1402
+ /**
1403
+ * Don't forget to change pFillFunc if necessary when you change the markup.
1404
+ * <span class="mainspan"></span> is required to use marker highlighting while typing. Highlighting is only working for the text
1405
+ * in this span. That means filter does not apply to additional text. See data parameter.
1406
+ */
1407
+ pMarkup: '<span class="' + pname + cmainspan + '">${text}</span> <span>${additional}</span>',
1408
+ /**
1409
+ * Change replacements lines in this function if necessary after changing pMarkup.
1410
+ * this refers to combobox
1411
+ * @param item {Object} item from data array
1412
+ * @param options {Object} plugin instance properties
1413
+ */
1414
+ pFillFunc: function(item, options) {
1415
+ return $('<p />').html(options.pMarkup
1416
+ .replace('${text}', item.text)
1417
+ .replace('${additional}', item.additional ? item.additional : '')
1418
+ );
1419
+ },
1420
+ /**
1421
+ * Animation settings.
1422
+ */
1423
+ animation: {
1424
+ duration: 'fast', // animation speed
1425
+ easing: 'swing' // easing effect
1426
+ },
1427
+ /**
1428
+ * Dropdown div max width
1429
+ */
1430
+ listMaxWidth: window.screen.width / 2,
1431
+ /**
1432
+ * Use this to handle long text options lists.
1433
+ * If true then long text options will take multiple lines. If false, then horizontal slider appears in list.
1434
+ */
1435
+ wrap: true,
1436
+ /**
1437
+ * Items list div maximum height (css property)
1438
+ */
1439
+ maxHeight: '',
1440
+ /**
1441
+ * Put main text in input while walking though the options with arrow keys
1442
+ */
1443
+ fillOnArrowPress: true,
1444
+ /**
1445
+ * Select hovered or first matching option on blur
1446
+ */
1447
+ fillOnBlur: false,
1448
+ /**
1449
+ * Blurs the search field on escape keypress
1450
+ */
1451
+ blurOnEscape: false,
1452
+ /**
1453
+ * Whether to set the first visible item as a value on tab key press (works only if search input is not empty).
1454
+ * If set to false then the default action is working (going to the next input on page).
1455
+ */
1456
+ fillOnTab: true,
1457
+ /**
1458
+ * If set to true dropdown arrow appears in the right corner of combobox
1459
+ */
1460
+ showDropDown: true,
1461
+ /**
1462
+ * Callback executes after finishing initialization.
1463
+ */
1464
+ callback: {
1465
+ func: $.noop, // this refers to combobox's div holder
1466
+ args: [] // arguments
1467
+ },
1468
+ beforeOpen: $.noop,
1469
+ beforeClose: $.noop,
1470
+ afterOpen: $.noop,
1471
+ afterClose: $.noop,
1472
+ /**
1473
+ * This option is for ajax loading (appending/prepending items). This function usage is:
1474
+ * function(value, direction) {
1475
+ * // value here is the edge value in the list (last for appending or first for prepending).
1476
+ * // direction here is the scrolling direction, which can be either 'top' or 'bottom'
1477
+ * // so you can do something like this:
1478
+ * var $t = $(this);
1479
+ * $.post('your url here' + (direction == 'top' ? '?prepend' : ''), {id: value}, function(res) {
1480
+ * $t.scombobox('fill', res, direction == 'top' ? 2 : 1); // 1 for prepending, 2 for appending
1481
+ * $t.data('pending', false); // this line is compulsory
1482
+ * });
1483
+ * }
1484
+ */
1485
+ autoLoad: $.noop,
1486
+ /**
1487
+ * Enables infinite scrolling for up and down arrows keys.
1488
+ * When autoLoad function provided then loopScrolling is set to false.
1489
+ */
1490
+ loopScrolling: true,
1491
+ /**
1492
+ * Placeholder for search input.
1493
+ */
1494
+ placeholder: ''
1495
+ };
1496
+
1497
+ /**
1498
+ * This function lets you override the default params without touching original plugin code.
1499
+ * Usage: $().scombobox.extendDefaults(yourDefaults);
1500
+ * @param options {Object} your custom defaults.
1501
+ */
1502
+ $.fn[pname].extendDefaults = function(options) {
1503
+ $.extend(true, $.fn[pname].defaults, options);
1504
+ };
1505
+ })(jQuery, document);
includes/js/jquery.scombobox.min.js ADDED
@@ -0,0 +1 @@
 
1
+ !function(t,e){"use strict";function i(t){return{fast:200,normal:400,slow:600}[t]||t}function a(t,e,i,a){if("function"!=typeof i){var s=t+("string"==typeof i?"."+i:"string"==typeof a?"."+a:"");e.trigger(s)}else n.call(e,t,i,a);return this}function n(t,e,i){var a=t+("string"==typeof i?"."+i:"");this.bind(a,e)}function s(){return JSON.parse(this.find(O+A).val()||"[]")}function l(){var e=t(this).find(O+P+" p"),i=t(this).children(O+A),a=[];e.each(function(){var e=t(this),i=e.find(":checkbox");i.prop("checked")&&a.push(e.data("value"))}),t(this).children("select").val(a),i.val(JSON.stringify(a))}function r(e){for(var i,a=t(this).find(O+P+" p"),n=t(this).children(O+A),s=[],l=0;l<a.length;l++){var r=a.eq(l),o=e.indexOf(r.data("value"));e.indexOf(r.data("value"))>=0?(i=r.find(":checkbox").prop("checked",!0),s.push(e[o])):r.find(":checkbox").prop("checked",!1)}t(this).children("select").val(e),i&&(i.trigger(y+"-chupdate",[!0]),n.val(JSON.stringify(s)))}function o(e){var i=t(this),a=this.data(y),n=i.children("select"),s=i.children(O+A),l=i.children(O+I),r=n.find("option").filter(function(){return this.value==e});return l.removeClass(y+L).siblings(O+j).removeClass(y+j+L),r.length?(i.find(O+P+" p").eq(r[0].index).addClass(y+M).siblings().removeClass(y+M),s.val(e).data("changed",!0),void n.val(e).change()):(i.find(O+P+" p").removeClass(y+M),n.children().prop("selected",!1),a.invalidAsValue?(a.highlightInvalid||(a.invalidAsValue?a.highlightInvalid:null===a.highlightInvalid))&&l.addClass(y+L).siblings(O+j).addClass(y+j+L):e="",s.val(e),void l.val(e))}function d(){if(!this.data("listenersAdded")){var i=this,a=i.data(y),n=null;this.on("keyup",O+I+", "+O+T,function(e){if(!([38,40,13,27,9,37,39,17,18,16,20,33,34,35,36].indexOf(e.which)>=0)){var i=function(e){if((e.ctrlKey||e.shiftKey||45!=e.which)&&(!e.ctrlKey||65!=e.which)){var i=a.fullMatch,n=a.highlight;n=i?n!==!1:!!n;var s=t(this),l=this.value.trim();a.filterIgnoreCase&&(l=l.toLowerCase()),a.filterIgnoreAccents&&String.prototype.latinize&&(l=l.latinize());var r=s.closest(O).children(O+P);m.call(r,"down",!0);var o=s.closest(O).find("select option");if(t(O+" "+O+P).each(function(){r[0]!=this&&m.call(t(this),"up")}),!l)return void r.children("p").show().each(function(){t(O+"-marker",this).contents().unwrap()});var d=a.hideSeparatorsOnSearch?"p":"p:not("+O+N+", "+O+V+")";r.children(d).hide(),o.each(function(){var e=t(this).text().trim();if(a.filterIgnoreCase&&(e=e.toLowerCase()),a.filterIgnoreAccents&&String.prototype.latinize&&(e=e.latinize()),i?e.indexOf(l)>=0:0==e.indexOf(l)){var s=a.filterIgnoreCase?"i":"",d=new RegExp("("+l.replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1")+")",i?s+"g":s),h=r.children("p:eq("+o.index(this)+"):not("+O+N+", "+O+V+")").show();n&&h.each(function(){t(O+"-marker",this).contents().unwrap();var e=t(O+F,this)[0];e.innerHTML=e.innerHTML.replace(d,'<span class="'+y+'-marker">$1</span>')})}})}},s=this,l=a.filterDelay;l?(clearTimeout(n),n=setTimeout(function(){i.call(s,e)},l)):i.call(s,e)}}),this.on("keydown",O+I,function(e){if([38,40,13,27,9].indexOf(e.which)>=0){9!=e.which&&e.preventDefault();var i,n,s=t(this).closest(O),l=s.children(O+P),r=t(O+M,l[0]),o=t("p:first",l[0]),d=a.loopScrolling,h=":not("+O+N+"):not("+O+V+")",c="default"==a.mode?a.fillOnArrowPress:!1;if(!l.is(":animated")){var p=this.value.trim();p=a.filterIgnoreCase?p.toLowerCase():p;var f=l.scrollTop();if(40==e.which){if(l.is(":hidden"))return void m.call(l,"down");if(0==r.length)i=o.is(":visible"+h)?o.addClass(y+M):o.nextAll(":visible"+h).first().addClass(y+M);else{if(!d&&!r.nextAll(":visible"+h).first().length)return;i=r.removeClass(y+M).nextAll(":visible"+h).first().addClass(y+M),0==i.length&&(i=o.is(":visible")?o.addClass(y+M):o.nextAll(":visible"+h).first().addClass(y+M)),0==i.length&&(i=o),n=i.position().top-l.position().top;var u=i.outerHeight();n+6*u>l.height()?n+6*u-l.height()>1.5*u?l.scrollTop(f+n):l.scrollTop(f+u):0>n&&l.scrollTop(f- -n)}c&&(this.value=i.find(O+F).text(),s.children(O+I).data("fillonarrow",!0))}else if(38==e.which){if(l.is(":visible")){if(!d&&!r.prevAll(":visible"+h).first().length)return;i=r.removeClass(y+M).prevAll(":visible"+h).first().addClass(y+M),0==i.length&&(i=t("p:visible"+h+":last",l[0]).addClass(y+M)),n=i.position().top-l.position().top,u=i.outerHeight(),3*u>n?l.scrollTop(f- -n-3*u):n>l.height()-3*u&&l.scrollTop(f+n-3*u),c&&(this.value=i.find(O+F).text(),s.children(O+I).data("fillonarrow",!0))}}else if(13==e.which){if(a.fillOnBlur)return void w(l).click();l.children(O+M).click(),"default"==a.mode&&m.call(l,"up")}else if(27==e.which){a.blurOnEscape?t(this).blur():t(this);l.is(":visible")&&(m.call(l,"up"),e.stopPropagation())}else if(9==e.which&&a.fillOnTab&&p){var v=l.children(O+M);v.length&&v.click()}}}}),this.on("change","select",function(e,i){var a=t(this).closest(O),n=t("option:selected",this).text();a.children(O+I).val(n).data("value",n);var s=a.children(O+A);return s.data("changed")?void s.data("changed",!1):i?(l.call(a),void s.change()):(s.change(),void m.call(a.children(O+P),"up"))}),this.on(y+"-chupdate",O+P+" p :checkbox",function(e,i){i&&(e.stopPropagation(),x.call(t(this).parent(),e,!0))}),this.on("click",O+P+" p",function(e){if(clearTimeout(k),e.stopPropagation(),!t(this).is(O+N+", "+O+V)){i.children(O+L).removeClass(y+L),i.children(O+j).removeClass(y+j+L);var a=t(this),n=a.parent(),s=n.children(),l=s.index(this);if("checkboxes"==i.data(y).mode)return void x.call(this,e);var r=n.closest(O).children("select");r.children("option").eq(l).prop("selected",!0),r.siblings(O+A).val(r.val()),r.change(),m.call(a.parent(),"up"),a.addClass(y+M).siblings().removeClass(y+M)}}),this.on("blur",O+I,function(n){var s=t(this),l=t(n.relatedTarget).closest(O);if(!(l.length>0&&l[0]===s.closest(O)[0])){k=setTimeout(function(){var a=t(this);i.data(y);this===e.activeElement&&a.data("silentfocus",!0),a.data("fillonarrow",!1),m.call(a.closest(O).children(O+P),"up")}.bind(this),200);var r=s.val().trim(),o=s.siblings(O+A),d=o.val();if(r){var h;s.siblings("select").find("option").each(function(){a.filterIgnoreCase?r.toLowerCase()==t(this).text().trim().toLowerCase()&&(h=this.value):r==t(this).text().trim()&&(h=this.value)}),h?o.val(h):o.val(a.invalidAsValue?r:"")}else o.val("");d!==o.val()&&o.change().data("changed",!0)}}),this.on("focus",O+I,function(){if(t(this).data("silentfocus"))return void t(this).data("silentfocus",!1);if(this.value.trim()){if(i.data(y).expandOnFocusWithValue||t(this).data("expandfocus"))if(i[y]("val")){var e=i.children(O+P);e.children().show(),m.call(e,"down")}else t(this).keyup()}else(i.data(y).expandOnFocus||t(this).data("expandfocus"))&&t(this).keyup();t(this).data("expandfocus",!1)}),this.on("click",O+I+"-div",function(){i.data(y).disabled||m.call(t(this).siblings(O+P),"down")}),this.on("click",O+I,function(e){var i=t(this).closest(O)[0];t(O).each(function(){this!=i&&t(this)[y]("close")}),e.stopPropagation()}),this.on("click",O+z,function(e){clearTimeout(k);var i=t(this),a=i.closest(O),n=a.children(O+P);n.is(":visible")?(m.call(n,"up"),a.children(O+I).data("silentfocus",!0).focus()):a.children(O+I).data("expandfocus",!0).focus()}),this.on("click",O+S,function(e){clearTimeout(k),e.stopPropagation();var n=t(this),s=n.parent(),l=i.children(O+P);l.children("p").eq(n.data("index")).find(":checkbox").prop("checked",!1),s.fadeOut(a.animation.duration),n.closest(O).children("select").trigger("change",[!0])}),a.autoLoad!=t.noop&&t(O+P,this).scroll(function(){var e=t(this),n=i.children("select"),s=e.scrollTop(),l=50;s>e.data("scrollTop")?this.scrollHeight-s-l<e.height()&&(i.data("pending")||(i.data("pending",!0),a.autoLoad.call(i,n.find("option[value]:last").val(),"bottom"))):s<e.height()/2&&(i.data("pending")||(i.data("pending",!0),a.autoLoad.call(i,n.find("option[value]:first").val(),"top"))),e.data("scrollTop",s)}).data("scrollTop",0),t(e).bind("click."+y,{thisIs:this},function(e){m.call(t(e.data.thisIs).children(O+P),"up")}),this.data("listenersAdded",!0)}}function h(e){if("string"==typeof e&&(e=t.parseJSON(e),null==e))return[];if(!e)return!1;if(!(e instanceof Array)){if("object"!=typeof e)return!1;"undefined"==typeof e.length&&(e.length=Object.keys(e).length),e=[].slice.call(e)}return e}function c(t){for(var e=0;e<t.length;e++)t[e].value&&t[e].text||t[e].hasOwnProperty("separator")||t.splice(e,1)}function p(e){for(var i=0;i<e.length;i++)e[i].value||t(e[i]).hasClass(y+N)||"optgroup"==e[i].tagName.toLowerCase()||t(e[i]).remove()}function f(t,e){var i=t.text.trim().toLowerCase(),a=e.text.trim().toLowerCase();return i>a?1:i==a?0:-1}function u(t){for(var e=0;e<t.length;e++)for(var i=e+1;i<t.length;i++)t[e]&&t[i]&&t[e].value==t[i].value&&t.splice(e,1)}function v(e){for(var i=0;i<e.length;i++)for(var a=i+1;a<e.length;a++)e[i]&&e[a]&&e[i].value==e[a].value&&"optgroup"!=e[i].tagName.toLowerCase()&&t(e[i]).remove()}function g(){var e,i=this.children(O+I),a=this.children("select"),n=this.data(y),s=i.val().trim();s=n.filterIgnoreCase?s.toLowerCase():s,a.find("option").each(function(){var i=t(this).text().trim();i=n.filterIgnoreCase?i.toLowerCase():i,i==s&&(e=this.value)});var l=!e&&s;l?(n.forbidInvalid?i.closest(O).find(O+I).val("").data("value",""):(n.highlightInvalid||(n.invalidAsValue?n.highlightInvalid:null===n.highlightInvalid))&&i.addClass(y+L).siblings(O+j).addClass(y+j+L),n.invalidAsValue||i.siblings("select, "+O+A).val("")):i.removeClass(y+L).siblings(O+j).removeClass(y+j+L)}function m(e,i){if(!this.is(":animated")&&this.length&&("up"!=e||!this.is(":hidden")||1!=this.length)){var a=this.parent().data(y).animation;t.easing[a.easing]||(console.warn("no such easing: "+a.easing),a.easing="swing");var n=this.parent(),s=n.data(y);"up"==e?(s.beforeClose.call(n),a.complete=function(){"checkboxes"!=s.mode&&g.call(n),s.afterClose.call(n)},this.slideUp(a).data("p-clicked-index",-1),n.children(O+z).removeClass(y+z+"-up")):(s.beforeOpen.call(n),a.complete=function(){s.afterOpen.call(n)},this.slideDown(a),n.children(O+z).addClass(y+z+"-up"),n.find(O+M).removeClass(y+M),t(O+"-marker",n).contents().unwrap(),n.children(O+P).children("p").show());var l=n.children(O+I);l.each(function(){var a=t(this);if(a.data("fillonarrow")&&!i&&a.data("fillonarrow",!1).val(a.data("value")),"down"==e){var l=this.value.trim();s.filterIgnoreCase&&(l=l.toLowerCase());var r=n.find("select option");r.each(function(){var e=t(this).text().trim();return s.filterIgnoreCase&&(e=e.toLowerCase()),e==l?(n.children(O+P).children("p:eq("+r.index(this)+"):not("+O+N+", "+O+V+")").first().addClass(y+M),!1):void 0})}})}}function x(e,a){var n=t(this),s=n.closest(O),l=n.parent(),r=l.children("p"),o=r.index(this),d=i(l.parent().data(y).animation.duration);if(!a){var h=n.find(":checkbox");t(e.target).is(":checkbox")||h.prop("checked",!h.prop("checked"));var c=h.prop("checked");if(e.shiftKey&&l.data("p-clicked-index")>=0)for(var p=l.data("p-clicked-index"),f=o>p?p:o,u=o>p?o:p,v=f;u>=v;v++)t(r[v]).find(":checkbox").prop("checked",c)}var g=s.find(O+q).prepend("<span />");s.find(O+q).fadeOut(d/5,function(){g.empty().show(),r.each(function(e){var i=t(this);i.find(":checkbox").prop("checked")&&g.append(t("<div />").addClass(y+D).append(t("<div />").addClass(y+D+"-text").text(i.find(O+F).text())).append(t("<div />").addClass(y+S).text("×").data("index",e)).fadeIn(1.5*d).attr("title",i.attr("title")))}),g.append('<div style="clear: both" />')}),l.data("p-clicked-index",o),n.closest(O).children("select").trigger("change",[!0])}function b(e,i){for(var a=this.data(y),n=this.find("select"),s=this.find(O+P),l=0;l<e.length;l++){if(e[l].hasOwnProperty("separator")){if(e[l].hasOwnProperty("header"))r=t('<p class="'+y+V+'" />').text(e[l].header);else var r=t('<p class="'+y+N+'" />');var o=t("<option />")}else o=t("<option />").val(e[l].value).text(e[l].text).prop("selected",!!e[l].selected),r=a.pFillFunc.call(this,e[l],a),"checkboxes"==a.mode&&r.prepend('<input type="checkbox" />');r.data("value",e[l].value),i?(n.prepend(o),s.prepend(r)):(n.append(o),s.append(r))}}function w(t){var e=t.children(O+M+":visible");return 0==e.length&&(e=t.children(":visible:first")),e}function C(t){if(null==t)return null;for(var e=Object.keys(t),i=0;i<e.length;i++){var a=e[i].replace(/-([a-z])/g,function(t){return t[1].toUpperCase()});e[i]!=a&&(t[a]=t[e[i]],delete t[e[i]]),"object"==typeof t[a]&&"data"!=a&&C(t[a])}return t}var k,y="scombobox",O="."+y,I="-display",A="-value",L="-invalid",T=I+"-div",D=T+"-item",S=D+"-remove",q=T+"-holder",P="-list",F="-mainspan",M="-hovered",N="-separator",V="-header",j="-dropdown-background",z="-dropdown-arrow",H="-disabled",$="-required",E=parseInt,J={init:function(){var e=this.find(O+P),i=this.find("select"),a=this.find(O+j),n=this.find(O+z),s=this.data(y);if(this.addClass(y),0==i.length&&this.append(t("<select />")),this.attr("id")&&i.removeAttr("id"),i.attr("multiple")&&(this.data(y).mode="checkboxes"),0==a.length&&this.append('<div class="'+y+j+'" />'),0==n.length&&this.append('<div class="'+y+z+'" />'),J.displayDropdown.call(this,s.showDropDown),"checkboxes"!=s.mode&&0==this.find(O+I).length){var l=t('<input class="'+y+I+'" type="text" />');l.attr("title",i.attr("title")),l.attr("placeholder",s.placeholder),this.append(l),this.height(+l.css("font-size")+ +l.css("padding-top")+ +l.css("padding-bottom"))}if(null!=s.tabindex&&this.find(O+I).attr("tabindex",s.tabindex),0==this.find(O+A).length&&this.append('<input class="'+y+A+'" type="hidden" />'),(this.find(O+I).is(":disabled")||s.disabled)&&this.find(O+j+", "+O+z).hide(),s.disabled&&(this.find(O+I).prop("disabled",!0),this.addClass(y+H)),(i.attr("required")||s.required)&&(this.find(O+I).prop("required","required"),this.addClass(y+$)),0==e.length&&this.append(e=t('<div class="'+y+P+'"></div>')),"checkboxes"==s.mode){this.addClass(y+"-checkboxes"),this.find(O+I).remove();var r=this.find(O+I+"-div");0==r.length&&(r=this.append('<div class="'+y+T+'"><div class="'+y+q+'" /></div>')),r.attr("title",i.attr("title")),e.insertAfter(this.find(O+I+"-div"));var o=this.find(O+q),h=t('<div class="'+y+D+'" id="'+y+'-test-item"><div class="'+y+D+'-text">x</div></div>');o.append(h.css("margin-left","-9999px").show());var c=h.height()+E(h.css("padding-top"))+E(h.css("padding-top"))+E(h.css("margin-top"))+E(h.css("margin-top"))+E(h.css("border-top-width"))+E(h.css("border-top-width"))+E(o.css("padding-top"))+E(o.css("padding-top"));this.find(O+I+"-div").css("min-height",c+"px"),h.remove()}else this.find(O+"-display-div").remove(),e.insertAfter(this.find(O+I));return e.css({"max-width":s.listMaxWidth,"max-height":s.maxHeight}),1==s.wrap&&e.css("white-space","normal"),s.autoLoad!=t.noop&&(s.loopScrolling=!1),d.call(this),this.data(y+"-init",!0),J.fill.call(this,s.data)},fill:function(e,i){var a=this.find("select").children("option, optgroup"),n=this.find("."+y+P),s=this.find("select");e=h(e);var l=this.data(y),r=l.mode;if(e?(l.removeDuplicates&&u(e),c(e),l.sort&&(e.sort(f),l.sortAsc||e.reverse()),i||(s.empty(),n.empty(),this.children(O+A+", "+O+I).val("")),b.call(this,e,2==i)):(l.removeDuplicates&&(v(a),p(a),a=this.find("select").children("option, optgroup")),0==a.length||a.each(function(){var e=t(this),i=t("<p />");if(i.attr("title",e.attr("title")),e.hasClass(y+N))e.hasClass(y+V)?n.append(i.addClass(y+V).text(e.text())):i.addClass(y+N);else{if("optgroup"==this.tagName.toLowerCase()){var a=e.attr("label"),s=t("option",this);return e.before("<option />"),e.after(s),e.remove(),n.append(a?i.addClass(y+V).text(a):i.addClass(y+N)),void s.each(function(){n.append(t("<p />").attr("title",this.title).append(t('<span class="'+y+F+'" />').text(t(this).text())).data("value",this.value))})}i.append(t('<span class="'+y+F+'" />').text(e.text())).data("value",this.value),"checkboxes"==r&&i.prepend('<input type="checkbox" />')}n.append(i)})),this.data(y+"-init")&&(l.callback.func.apply(this,l.callback.args),this.data(y+"-init",!1)),a=this.find("select").children("option"),!l.empty)if("checkboxes"!=r)this[y]("val",a.filter("option:selected:last").val());else{var o=a.filter(":selected").map(function(){return t(this).val()}).get();this[y]("val",o)}return this},clear:function(){return this.children("select").empty(),this.children(O+P).empty().width(""),this.children(O+I).removeClass(y+L),this.children(O+j).removeClass(y+j+L),this},data:function(t){return 0==arguments.length?this.data(y).data:(this.data(y).data=t,this)},disabled:function(t){var e=this.data(y).mode;return 0==arguments.length?"checkboxes"==e?this.hasClass(y+H):this.children(O+I).prop("disabled"):(t=!!t,this.children(O+I).prop("disabled",t),t?(this.addClass(y+H),this.children(O+j+", "+O+z).hide()):(this.removeClass(y+H),this.children(O+j+", "+O+z).show()),this)},tabindex:function(t){var e=this.find(O+I);return 0==arguments.length?e.attr("tabindex"):(e.attr("tabindex",t),this)},options:function(e){return 0==arguments.length?this.data(y):(t.extend(!0,this.data(y),C(e)),this)},val:function(t){var e=this.data(y),i=e.mode;if(0==arguments.length){if("default"==i)var a=this.find(O+A).val();return"default"==i?this.find(O+I).is(":disabled")?"":a:"checkboxes"==i?s.call(this):null}return"default"==i?o.call(this,t):"checkboxes"==i&&r.call(this,t),this},open:function(){return m.call(this.children(O+P),"down"),this},close:function(){return m.call(this.children(O+P),"up"),this},change:function(t,e){return a.call(this,"change",this.children(O+A),t,e)},focus:function(t,e){return a.call(this,"focus",this.children(O+I),t,e)},blur:function(t,e){return a.call(this,"blur",this.children(O+I),t,e)},keyup:function(t,e){return a.call(this,"keyup",this.children(O+I),t,e)},keydown:function(t,e){return a.call(this,"keydown",this.children(O+I),t,e)},keypress:function(t,e){return a.call(this,"keypress",this.children(O+I),t,e)},click:function(t,e){return a.call(this,"click",this.children(O+I),t,e)},mousedown:function(t,e){return a.call(this,"mousedown",this.children(O+I),t,e)},clickDropdown:function(t,e){return a.call(this,"click",this.children(O+z),t,e)},toSelect:function(){var t=this.children("select").insertAfter(this);return this.data(y).reassignId&&t.attr("id",this.attr("id")),this.remove(),t},displayDropdown:function(t){return arguments.length?t?this.children(O+z+", "+O+j).show():this.children(O+z+", "+O+j).hide():this.data(y).showDropdown?this.children(O+z+", "+O+j).show():this.children(O+z+", "+O+j).hide(),this},placeholder:function(t){var e=this.children(O+I);return arguments.length?(e.attr("placeholder",t),this):e.attr("placeholder")}};t.fn[y]=function(e){if("string"==typeof e){this.length||t.error("Calling "+y+"."+e+"() method on empty collection"),null==this.data(y+"-init")&&t.error("Calling "+y+"."+e+"() method prior to initialization");var i=J[e];i||t.error("No such method: "+e+" in jQuery."+y+"()")}else{if(!(["object","undefined"].indexOf(typeof e)>=0))return t.error("Incorrect usage"),this;var a=t.extend(!0,{},t.fn[y].defaults,C(e))}return i?i.apply(this,Array.prototype.slice.call(arguments,1)):this.each(function(){var e=t(this);e.parent().hasClass(y)||(e.is("select")&&(e.wrap("<div />"),a.reassignId&&e.parent().attr("id",e.attr("id")),e=e.parent()),e.data(y,t.extend(!0,{},a)),J.init.apply(e))})},t.fn[y].defaults={data:null,empty:!1,required:!1,disabled:!1,sort:!0,sortAsc:!0,removeDuplicates:!0,fullMatch:!1,highlight:null,filterIgnoreCase:!0,filterIgnoreAccents:!1,filterDelay:0,hideSeparatorsOnSearch:!1,expandOnFocus:!0,expandOnFocusWithValue:!0,tabindex:null,forbidInvalid:!1,invalidAsValue:!1,highlightInvalid:null,reassignId:!0,mode:"default",pMarkup:'<span class="'+y+F+'">${text}</span> <span>${additional}</span>',pFillFunc:function(e,i){return t("<p />").html(i.pMarkup.replace("${text}",e.text).replace("${additional}",e.additional?e.additional:""))},animation:{duration:"fast",easing:"swing"},listMaxWidth:window.screen.width/2,wrap:!0,maxHeight:"",fillOnArrowPress:!0,fillOnBlur:!1,blurOnEscape:!1,fillOnTab:!0,showDropDown:!0,callback:{func:t.noop,args:[]},beforeOpen:t.noop,beforeClose:t.noop,afterOpen:t.noop,afterClose:t.noop,autoLoad:t.noop,loopScrolling:!0,placeholder:""},t.fn[y].extendDefaults=function(e){t.extend(!0,t.fn[y].defaults,e)}}(jQuery,document);
includes/js/missed.js ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // add missing native JS stuff if needed
2
+ if (!String.prototype.trim) {
3
+ String.prototype.trim = function () {
4
+ return this.replace(/^\s+|\s+$/g, '');
5
+ };
6
+ }
7
+ if (typeof console == 'undefined') {
8
+ (function() {
9
+ var methods = ['log', 'info', 'warn', 'error', 'debug', 'group', 'groupCollapsed', 'groupEnd', 'dir', 'time', 'timeEnd', 'trace'];
10
+ window.console = new Object();
11
+ for (var i in methods) {
12
+ window.console[methods[i]] = function(){};
13
+ }
14
+ })();
15
+ }
16
+ if (!Array.prototype.indexOf) {
17
+ Array.prototype.indexOf = function (searchElement /*, fromIndex */) {
18
+ "use strict";
19
+ if (this == null) {
20
+ throw new TypeError();
21
+ }
22
+ var t = Object(this);
23
+ var len = t.length >>> 0;
24
+
25
+ if (len === 0) {
26
+ return -1;
27
+ }
28
+ var n = 0;
29
+ if (arguments.length > 1) {
30
+ n = Number(arguments[1]);
31
+ if (n != n) { // shortcut for verifying if it's NaN
32
+ n = 0;
33
+ } else if (n != 0 && n != Infinity && n != -Infinity) {
34
+ n = (n > 0 || -1) * Math.floor(Math.abs(n));
35
+ }
36
+ }
37
+ if (n >= len) {
38
+ return -1;
39
+ }
40
+ var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
41
+ for (; k < len; k++) {
42
+ if (k in t && t[k] === searchElement) {
43
+ return k;
44
+ }
45
+ }
46
+ return -1;
47
+ }
48
+ }
49
+ if (!Object.keys) {
50
+ Object.keys = (function () {
51
+ 'use strict';
52
+ var hasOwnProperty = Object.prototype.hasOwnProperty,
53
+ hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
54
+ dontEnums = [
55
+ 'toString',
56
+ 'toLocaleString',
57
+ 'valueOf',
58
+ 'hasOwnProperty',
59
+ 'isPrototypeOf',
60
+ 'propertyIsEnumerable',
61
+ 'constructor'
62
+ ],
63
+ dontEnumsLength = dontEnums.length;
64
+
65
+ return function (obj) {
66
+ if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
67
+ throw new TypeError('Object.keys called on non-object');
68
+ }
69
+
70
+ var result = [], prop, i;
71
+
72
+ for (prop in obj) {
73
+ if (hasOwnProperty.call(obj, prop)) {
74
+ result.push(prop);
75
+ }
76
+ }
77
+
78
+ if (hasDontEnumBug) {
79
+ for (i = 0; i < dontEnumsLength; i++) {
80
+ if (hasOwnProperty.call(obj, dontEnums[i])) {
81
+ result.push(dontEnums[i]);
82
+ }
83
+ }
84
+ }
85
+ return result;
86
+ };
87
+ }());
88
+ }
js/ad-inserter.js CHANGED
@@ -1,4 +1,4 @@
1
- var javascript_version = "2.3.1";
2
  var ignore_key = true;
3
  var start = 1;
4
  var end = 16;
@@ -68,6 +68,10 @@ var AI_ADSENSE_IN_ARTICLE = 2;
68
  var AI_ADSENSE_IN_FEED = 3;
69
  var AI_ADSENSE_MATCHED_CONTENT = 4;
70
 
 
 
 
 
71
  var AI_HTML_INSERTION_CLIENT_SIDE = 0;
72
  var AI_HTML_INSERTION_CLIENT_SIDE_DOM_READY = 1;
73
  var AI_HTML_INSERTION_SEREVR_SIDE = 2;
@@ -1046,21 +1050,29 @@ jQuery(document).ready(function($) {
1046
  }
1047
 
1048
  function process_adsense_elements (block) {
1049
- var adsense_type = parseInt ($("select#adsense-type-" + block +" option:selected").attr ('value'));
1050
- var adsense_responsive = $("#adsense-responsive-" + block).is(":checked");
 
 
 
 
 
 
 
 
1051
 
1052
  $('#tab-adsense-' + block + ' .adsense-layout').css ('visibility', 'hidden');
 
1053
  $('#tab-adsense-' + block + ' .adsense-size').css ('visibility', 'hidden');
1054
- $('#tab-adsense-' + block + ' .adsense-responsive').css ('visibility', 'hidden');
1055
 
1056
  switch (adsense_type) {
1057
  case AI_ADSENSE_STANDARD:
1058
- $('#tab-adsense-' + block + ' .adsense-responsive').css ('visibility', 'visible');
1059
- if (!adsense_responsive) $('#tab-adsense-' + block + ' .adsense-size').css ('visibility', 'visible');
1060
  break;
1061
  case AI_ADSENSE_LINK:
1062
- $('#tab-adsense-' + block + ' .adsense-responsive').css ('visibility', 'visible');
1063
- if (!adsense_responsive) $('#tab-adsense-' + block + ' .adsense-size').css ('visibility', 'visible');
1064
  break;
1065
  case AI_ADSENSE_IN_ARTICLE:
1066
  break;
@@ -1894,8 +1906,8 @@ jQuery(document).ready(function($) {
1894
  process_adsense_elements (block);
1895
  });
1896
 
1897
- $("input#adsense-responsive-"+tab).change (function() {
1898
- var block = $(this).attr('id').replace ("adsense-responsive-", "");
1899
  process_adsense_elements (block);
1900
  });
1901
 
@@ -2026,6 +2038,8 @@ jQuery(document).ready(function($) {
2026
  $.post (ajaxurl, {'action': 'ai_ajax_backend', 'ai_check': nonce, 'import-code': $.base64Encode (get_editor_text (block))}
2027
  ).done (function (data) {
2028
  if (data != '') {
 
 
2029
  try {
2030
  var code_data = JSON.parse (data);
2031
  } catch (error) {
@@ -2048,18 +2062,37 @@ jQuery(document).ready(function($) {
2048
  $("#open-new-tab-" + block).attr('checked', code_data ['target'] == '_blank');
2049
  break;
2050
  case AI_CODE_ADSENSE:
 
2051
  $("#adsense-publisher-id-" + block).val (code_data ['adsense-publisher-id']);
2052
  $("#adsense-ad-slot-id-" + block).val (code_data ['adsense-ad-slot-id']);
2053
 
2054
  $("#adsense-type-" + block).val (code_data ['adsense-type']);
2055
- $("#adsense-responsive-" + block).prop ('checked', code_data ['adsense-responsive']);
2056
- $("#adsense-width-" + block).val (code_data ['adsense-width']);
2057
- $("#adsense-height-" + block).val (code_data ['adsense-height']);
 
 
 
 
 
2058
  $("#adsense-amp-" + block).val (code_data ['adsense-amp']);
2059
 
2060
  $("#adsense-layout-" + block).val (code_data ['adsense-layout']);
2061
- $("#adsense-layout-key-" + block).val (code_data ['adsense-layout-key']);
 
 
 
 
 
 
 
 
 
 
2062
 
 
 
 
2063
  process_adsense_elements (block);
2064
  break;
2065
  case AI_CODE_UNKNOWN:
@@ -2076,6 +2109,7 @@ jQuery(document).ready(function($) {
2076
  });
2077
 
2078
  $("#generate-code-"+tab).click (function () {
 
2079
  $(this).next ("label").find ('.checkbox-icon').addClass("on");
2080
 
2081
  var block = $(this).attr('id').replace ("generate-code-", "");
@@ -2092,15 +2126,37 @@ jQuery(document).ready(function($) {
2092
  code_data ['target'] = '_blank';
2093
  break;
2094
  case AI_CODE_ADSENSE:
 
 
2095
  code_data ['adsense-publisher-id'] = $("#adsense-publisher-id-" + block).val ();
2096
  code_data ['adsense-ad-slot-id'] = $("#adsense-ad-slot-id-" + block).val ();
2097
  code_data ['adsense-type'] = parseInt ($("select#adsense-type-" + block +" option:selected").attr ('value'));
2098
- code_data ['adsense-responsive'] = $("#adsense-responsive-" + block).is(":checked") ? 1 : 0;
2099
- code_data ['adsense-width'] = $("#adsense-width-" + block).val ();
2100
- code_data ['adsense-height'] = $("#adsense-height-" + block).val ();
 
 
 
 
 
 
 
2101
  code_data ['adsense-amp'] = parseInt ($("select#adsense-amp-" + block +" option:selected").attr ('value'));
2102
  code_data ['adsense-layout'] = $("#adsense-layout-" + block).val ();
2103
  code_data ['adsense-layout-key'] = $("#adsense-layout-key-" + block).val ();
 
 
 
 
 
 
 
 
 
 
 
 
 
2104
  break;
2105
  case AI_CODE_UNKNOWN:
2106
  // if (debug) console.log ("AI GENERATE CODE:", code_type);
@@ -2210,6 +2266,14 @@ jQuery(document).ready(function($) {
2210
  $("#server-side-insertion-"+tab).hide (); else
2211
  $("#server-side-insertion-"+tab).show ();
2212
  });
 
 
 
 
 
 
 
 
2213
  }
2214
 
2215
  function import_rotation_code (block) {
1
+ var javascript_version = "2.3.2";
2
  var ignore_key = true;
3
  var start = 1;
4
  var end = 16;
68
  var AI_ADSENSE_IN_FEED = 3;
69
  var AI_ADSENSE_MATCHED_CONTENT = 4;
70
 
71
+ var AI_ADSENSE_SIZE_FIXED = 0;
72
+ var AI_ADSENSE_SIZE_RESPONSIVE = 1;
73
+ var AI_ADSENSE_SIZE_FIXED_BY_VIEWPORT = 2;
74
+
75
  var AI_HTML_INSERTION_CLIENT_SIDE = 0;
76
  var AI_HTML_INSERTION_CLIENT_SIDE_DOM_READY = 1;
77
  var AI_HTML_INSERTION_SEREVR_SIDE = 2;
1050
  }
1051
 
1052
  function process_adsense_elements (block) {
1053
+ var adsense_type = parseInt ($("select#adsense-type-" + block +" option:selected").attr ('value'));
1054
+ var adsense_size = parseInt ($("select#adsense-size-" + block +" option:selected").attr ('value'));
1055
+
1056
+ if ((adsense_type == AI_ADSENSE_STANDARD || adsense_type == AI_ADSENSE_LINK) && adsense_size == AI_ADSENSE_SIZE_FIXED_BY_VIEWPORT) {
1057
+ $('#adsense-layout-' + block).hide ();
1058
+ $('#adsense-viewports-' + block).show ();
1059
+ } else {
1060
+ $('#adsense-layout-' + block).show ();
1061
+ $('#adsense-viewports-' + block).hide ();
1062
+ }
1063
 
1064
  $('#tab-adsense-' + block + ' .adsense-layout').css ('visibility', 'hidden');
1065
+ $('#tab-adsense-' + block + ' .adsense-fixed-size').css ('visibility', 'hidden');
1066
  $('#tab-adsense-' + block + ' .adsense-size').css ('visibility', 'hidden');
 
1067
 
1068
  switch (adsense_type) {
1069
  case AI_ADSENSE_STANDARD:
1070
+ $('#tab-adsense-' + block + ' .adsense-size').css ('visibility', 'visible');
1071
+ if (adsense_size == AI_ADSENSE_SIZE_FIXED) $('#tab-adsense-' + block + ' .adsense-fixed-size').css ('visibility', 'visible');
1072
  break;
1073
  case AI_ADSENSE_LINK:
1074
+ $('#tab-adsense-' + block + ' .adsense-size').css ('visibility', 'visible');
1075
+ if (adsense_size == AI_ADSENSE_SIZE_FIXED) $('#tab-adsense-' + block + ' .adsense-fixed-size').css ('visibility', 'visible');
1076
  break;
1077
  case AI_ADSENSE_IN_ARTICLE:
1078
  break;
1906
  process_adsense_elements (block);
1907
  });
1908
 
1909
+ $("select#adsense-size-"+tab).change (function() {
1910
+ var block = $(this).attr('id').replace ("adsense-size-", "");
1911
  process_adsense_elements (block);
1912
  });
1913
 
2038
  $.post (ajaxurl, {'action': 'ai_ajax_backend', 'ai_check': nonce, 'import-code': $.base64Encode (get_editor_text (block))}
2039
  ).done (function (data) {
2040
  if (data != '') {
2041
+ $('#ai-error-container').hide ();
2042
+
2043
  try {
2044
  var code_data = JSON.parse (data);
2045
  } catch (error) {
2062
  $("#open-new-tab-" + block).attr('checked', code_data ['target'] == '_blank');
2063
  break;
2064
  case AI_CODE_ADSENSE:
2065
+ $("#adsense-comment-" + block).val (code_data ['adsense-comment']);
2066
  $("#adsense-publisher-id-" + block).val (code_data ['adsense-publisher-id']);
2067
  $("#adsense-ad-slot-id-" + block).val (code_data ['adsense-ad-slot-id']);
2068
 
2069
  $("#adsense-type-" + block).val (code_data ['adsense-type']);
2070
+ $("#adsense-size-" + block).val (code_data ['adsense-size']);
2071
+
2072
+ var ad_size = '';
2073
+ if (code_data ['adsense-width'] != '' && code_data ['adsense-height'] != '') {
2074
+ ad_size = code_data ['adsense-width'] + 'x' + code_data ['adsense-height'];
2075
+ }
2076
+ $('#tab-adsense-' + block + ' .adsense-ad-size.fixed').parent ().find ('.scombobox-display').val (ad_size);
2077
+
2078
  $("#adsense-amp-" + block).val (code_data ['adsense-amp']);
2079
 
2080
  $("#adsense-layout-" + block).val (code_data ['adsense-layout']);
2081
+ $("#adsense-layout-key-" + block).val (decodeURIComponent (code_data ['adsense-layout-key']));
2082
+
2083
+ if ($("#adsense-size-" + block).val () == AI_ADSENSE_SIZE_FIXED_BY_VIEWPORT) {
2084
+ $('#tab-adsense-' + block + ' tr.adsense-viewport').each (function (index) {
2085
+ var width = code_data ['adsense-sizes'][index][0];
2086
+ var height = code_data ['adsense-sizes'][index][1];
2087
+
2088
+ var ad_size = '';
2089
+ if (width != '' && height != '') {
2090
+ ad_size = width + 'x' + height;
2091
+ }
2092
 
2093
+ $(this).find ('.adsense-ad-size').parent ().find ('.scombobox-display').val (ad_size);
2094
+ });
2095
+ }
2096
  process_adsense_elements (block);
2097
  break;
2098
  case AI_CODE_UNKNOWN:
2109
  });
2110
 
2111
  $("#generate-code-"+tab).click (function () {
2112
+ $('#ai-error-container').hide ();
2113
  $(this).next ("label").find ('.checkbox-icon').addClass("on");
2114
 
2115
  var block = $(this).attr('id').replace ("generate-code-", "");
2126
  code_data ['target'] = '_blank';
2127
  break;
2128
  case AI_CODE_ADSENSE:
2129
+ code_data ['block'] = block;
2130
+ code_data ['adsense-comment'] = $("#adsense-comment-" + block).val ();
2131
  code_data ['adsense-publisher-id'] = $("#adsense-publisher-id-" + block).val ();
2132
  code_data ['adsense-ad-slot-id'] = $("#adsense-ad-slot-id-" + block).val ();
2133
  code_data ['adsense-type'] = parseInt ($("select#adsense-type-" + block +" option:selected").attr ('value'));
2134
+ code_data ['adsense-size'] = parseInt ($("select#adsense-size-" + block +" option:selected").attr ('value'));
2135
+
2136
+ var ad_size = $('#tab-adsense-' + block + ' .adsense-ad-size.fixed').parent ().find ('.scombobox-display').val ().trim ().toLowerCase ().split ('x');
2137
+ code_data ['adsense-width'] = '';
2138
+ code_data ['adsense-height'] = '';
2139
+ if (ad_size.length == 2) {
2140
+ code_data ['adsense-width'] = parseInt (ad_size [0]);
2141
+ code_data ['adsense-height'] = parseInt (ad_size [1]);
2142
+ }
2143
+
2144
  code_data ['adsense-amp'] = parseInt ($("select#adsense-amp-" + block +" option:selected").attr ('value'));
2145
  code_data ['adsense-layout'] = $("#adsense-layout-" + block).val ();
2146
  code_data ['adsense-layout-key'] = $("#adsense-layout-key-" + block).val ();
2147
+
2148
+ if (code_data ['adsense-size'] == AI_ADSENSE_SIZE_FIXED_BY_VIEWPORT) {
2149
+ var viewport_sizes = new Array();
2150
+ $('#tab-adsense-' + block + ' tr.adsense-viewport').each (function (index) {
2151
+ var ad_size = $(this).find ('.adsense-ad-size').parent ().find ('.scombobox-display').val ().trim ().toLowerCase ().split ('x');
2152
+ var adsense_size = {'width': '', 'height': ''};
2153
+ if (ad_size.length == 2) {
2154
+ adsense_size = {'width': parseInt (ad_size [0]), 'height': parseInt (ad_size [1])};
2155
+ }
2156
+ viewport_sizes.push (adsense_size);
2157
+ });
2158
+ code_data ['adsense-viewports'] = viewport_sizes;
2159
+ }
2160
  break;
2161
  case AI_CODE_UNKNOWN:
2162
  // if (debug) console.log ("AI GENERATE CODE:", code_type);
2266
  $("#server-side-insertion-"+tab).hide (); else
2267
  $("#server-side-insertion-"+tab).show ();
2268
  });
2269
+
2270
+ $("#tab-" + tab + " .adsense-ad-size").scombobox({
2271
+ showDropDown: false,
2272
+ invalidAsValue: true,
2273
+ animation: {
2274
+ duration: 50,
2275
+ }
2276
+ });
2277
  }
2278
 
2279
  function import_rotation_code (block) {
readme.txt CHANGED
@@ -6,7 +6,7 @@ Tags: ads, adsense, ad management, advertising manager, advanced contextual ads,
6
  Requires at least: 4.0
7
  Tested up to: 4.9
8
  Requires PHP: 5.3
9
- Stable tag: 2.3.0
10
  License: GPLv3
11
 
12
  Insert and manage ads: AdSense, Amazon, banners, ad rotation, sticky ad widgets, shortcodes, AMP, PHP, HTML, CSS, form, tracking, header, footer code
@@ -17,7 +17,8 @@ Ad management plugin with many advanced advertising features. Supports all kinds
17
 
18
  Ad Inserter is more than just ad manager plugin. It provides many advanced options to insert any opt-in form, Javascript, CSS, HTML, PHP, analytics, tracking or advert code anywhere on the page.
19
 
20
- **Ad Inserter can insert ads where other plugins fail**. It's all about the settings.
 
21
 
22
  **Features**
23
 
@@ -25,7 +26,7 @@ Ad Inserter is more than just ad manager plugin. It provides many advanced optio
25
  * AdSense integration
26
  * Syntax highlighting editor
27
  * Code preview with visual CSS editor
28
- * Automatically inserts ads in posts and pages
29
  * Insert before or after post
30
  * Insert before or after content
31
  * Insert before or after paragraph
@@ -91,7 +92,7 @@ Run a WordPress related blog? Interested in reviewing Ad Inserter Pro? <a href="
91
 
92
  Ad Inserter Wordpress plugin is an advanced advertising manager - it has many features and options to automate ad insertion and to optimally monetize your website on desktop, tablet and phone displays. It provides many simple ways to insert any Javascript, HTML, PHP or advert code anywhere on the page. For best ad placement and to use optimal advertising positions please read the user manual to get the most of the plugin.
93
 
94
- * Check <a href="http://adinserter.pro/documentation" target="_blank">Ad Inserter documentation page</a> for detailed description of all the features and some <a href="http://adinserter.pro/settings" target="_blank">common settings</a> for quick start
95
  * Download **PDF user guide** for Ad Inserter: go to <a href="http://adinserter.pro/" target="_blank">Ad Inserter Pro plugin</a> page and below you can find button for free download of Ad Inserter User Guide
96
 
97
  **AdSense integration**
@@ -118,7 +119,7 @@ Check <a href="https://affiliate-program.amazon.com/help/topic/t405" target="_bl
118
 
119
  Ad Inserter is not just another plugin for WordPress ads. Do you enjoy finding the right plugin to solve a particular problem on your site? For example:
120
 
121
- * ad management and ad injection
122
  * to insert AdSense or Media.net ads
123
  * to insert affiliate ads (CJ Affiliate by Conversant, ClickBank, ShareASale, Rakuten LinkShare, etc.)
124
  * to insert ads between paragraphs
@@ -783,6 +784,11 @@ AD CODE RIGHT
783
 
784
  == Changelog ==
785
 
 
 
 
 
 
786
  = 2.3.1 =
787
  - Added support for server-side insertion before/after any HTML element
788
  - Few minor bug fixes
@@ -981,6 +987,11 @@ AD CODE RIGHT
981
 
982
  == Upgrade Notice ==
983
 
 
 
 
 
 
984
  = 2.3.1 =
985
  Added support for server-side insertion before/after any HTML element;
986
  Few minor bug fixes
6
  Requires at least: 4.0
7
  Tested up to: 4.9
8
  Requires PHP: 5.3
9
+ Stable tag: 2.3.1
10
  License: GPLv3
11
 
12
  Insert and manage ads: AdSense, Amazon, banners, ad rotation, sticky ad widgets, shortcodes, AMP, PHP, HTML, CSS, form, tracking, header, footer code
17
 
18
  Ad Inserter is more than just ad manager plugin. It provides many advanced options to insert any opt-in form, Javascript, CSS, HTML, PHP, analytics, tracking or advert code anywhere on the page.
19
 
20
+ **Ad Inserter can insert ads where other plugins fail**.
21
+ It's all about the settings.
22
 
23
  **Features**
24
 
26
  * AdSense integration
27
  * Syntax highlighting editor
28
  * Code preview with visual CSS editor
29
+ * Automatically inserts ads on posts and pages
30
  * Insert before or after post
31
  * Insert before or after content
32
  * Insert before or after paragraph
92
 
93
  Ad Inserter Wordpress plugin is an advanced advertising manager - it has many features and options to automate ad insertion and to optimally monetize your website on desktop, tablet and phone displays. It provides many simple ways to insert any Javascript, HTML, PHP or advert code anywhere on the page. For best ad placement and to use optimal advertising positions please read the user manual to get the most of the plugin.
94
 
95
+ * Check <a href="http://adinserter.pro/documentation" target="_blank">Ad Inserter documentation pages</a> for detailed description of all the features and some <a href="http://adinserter.pro/settings" target="_blank">common settings</a> for quick start
96
  * Download **PDF user guide** for Ad Inserter: go to <a href="http://adinserter.pro/" target="_blank">Ad Inserter Pro plugin</a> page and below you can find button for free download of Ad Inserter User Guide
97
 
98
  **AdSense integration**
119
 
120
  Ad Inserter is not just another plugin for WordPress ads. Do you enjoy finding the right plugin to solve a particular problem on your site? For example:
121
 
122
+ * for ad management and ad injection
123
  * to insert AdSense or Media.net ads
124
  * to insert affiliate ads (CJ Affiliate by Conversant, ClickBank, ShareASale, Rakuten LinkShare, etc.)
125
  * to insert ads between paragraphs
784
 
785
  == Changelog ==
786
 
787
+ = 2.3.2 =
788
+ - Added AdSense code generator for ad sizes using CSS media queries
789
+ - Fix for slow updates caused by changed user agent (credits Olivier Langlois)
790
+ - Fix for client-side insertion of non-English characters before/after HTML element
791
+
792
  = 2.3.1 =
793
  - Added support for server-side insertion before/after any HTML element
794
  - Few minor bug fixes
987
 
988
  == Upgrade Notice ==
989
 
990
+ = 2.3.2 =
991
+ Added AdSense code generator for ad sizes using CSS media queries;
992
+ Fix for slow updates caused by changed user agent (credits Olivier Langlois);
993
+ Fix for client-side insertion of non-English characters before/after HTML element
994
+
995
  = 2.3.1 =
996
  Added support for server-side insertion before/after any HTML element;
997
  Few minor bug fixes
settings.php CHANGED
@@ -647,19 +647,23 @@ function generate_settings_form (){
647
  </div>
648
 
649
  <div id="tab-adsense-<?php echo $block; ?>" class="responsive-table rounded">
650
- <table class="ai-settings-table" style="">
 
651
  <tr>
652
  <td>
653
- Publisher ID
654
  </td>
655
- <td style="width: 50%; padding-left: 7px;">
656
- <input id="adsense-publisher-id-<?php echo $block; ?>" style="width: 100%;" type="text" size="30" maxlength="30" />
657
  </td>
658
- <td class="adsense-layout" style="padding-left: 7px;">
659
- Layout
 
 
 
660
  </td>
661
- <td class="adsense-layout" style="width: 50%; padding-left: 7px;">
662
- <input id="adsense-layout-<?php echo $block; ?>" style="width: 100%;" type="text" size="80" maxlength="100" />
663
  </td>
664
  </tr>
665
 
@@ -667,15 +671,9 @@ function generate_settings_form (){
667
  <td>
668
  Ad Slot ID
669
  </td>
670
- <td style="width: 50%; padding-left: 7px;">
671
  <input id="adsense-ad-slot-id-<?php echo $block; ?>" style="width: 100%;" type="text" size="30" maxlength="30" />
672
  </td>
673
- <td class="adsense-layout" style="padding-left: 7px;">
674
- Layout Key
675
- </td>
676
- <td class="adsense-layout" style="width: 50%; padding-left: 7px;">
677
- <input id="adsense-layout-key-<?php echo $block; ?>" style="width: 100%;" type="text" size="80" maxlength="100" />
678
- </td>
679
  </tr>
680
 
681
  <tr>
@@ -691,25 +689,15 @@ function generate_settings_form (){
691
  <option value="<?php echo AI_ADSENSE_MATCHED_CONTENT; ?>"><?php echo AI_TEXT_MATCHED_CONTENT; ?></option>
692
  <option value="<?php echo AI_ADSENSE_AUTO; ?>"><?php echo AI_TEXT_AUTO; ?></option>
693
  </select>
694
- <div class="adsense-responsive" style="float: right; margin-top: 3px;">
695
- <input type="checkbox" id="adsense-responsive-<?php echo $block; ?>" />
696
- <label for="adsense-responsive-<?php echo $block; ?>">Responsive</label>
 
 
 
 
697
  </div>
698
  </td>
699
- <td>
700
- </td>
701
- <td style="padding-left: 7px;">
702
- <span class="adsense-size">
703
- Width
704
- <input id="adsense-width-<?php echo $block; ?>" style="width: 50px;" type="text" size="5" maxlength="5" />
705
- px
706
- <span style="float: right;">
707
- Height
708
- <input id="adsense-height-<?php echo $block; ?>" style="width: 50px;" type="text" size="5" maxlength="5" />
709
- px
710
- </span>
711
- </span>
712
- </td>
713
  </tr>
714
 
715
  <tr>
@@ -723,18 +711,115 @@ function generate_settings_form (){
723
  <option value="<?php echo AI_ADSENSE_AMP_BELOW_THE_FOLD; ?>"><?php echo AI_TEXT_BELOW_THE_FOLD; ?></option>
724
  </select>
725
  </td>
 
 
 
726
  <td>
727
  </td>
728
  <td>
729
  <?php if (defined ('AI_ADSENSE_API')) : ?>
730
  <?php if (!defined ('AI_ADSENSE_AUTHORIZATION_CODE')) : ?>
731
- <button type="button" class='ai-button adsense-list' style="display: none; float: right; margin: 0 -3px -14px 0;" title="Show AdSense ad units from your account">AdSense ad units</button>
732
  <?php endif; ?>
733
  <?php endif; ?>
734
  </td>
735
  </tr>
 
736
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
737
  </table>
 
738
  <div style="clear: both;"></div>
739
 
740
  </div>
647
  </div>
648
 
649
  <div id="tab-adsense-<?php echo $block; ?>" class="responsive-table rounded">
650
+
651
+ <table class="ai-settings-table left">
652
  <tr>
653
  <td>
654
+ Comment
655
  </td>
656
+ <td style="width: 100%; padding-left: 7px;">
657
+ <input id="adsense-comment-<?php echo $block; ?>" style="width: 100%;" type="text" size="30" maxlength="50" />
658
  </td>
659
+ </tr>
660
+
661
+ <tr>
662
+ <td>
663
+ Publisher ID
664
  </td>
665
+ <td style="width: 100%; padding-left: 7px;">
666
+ <input id="adsense-publisher-id-<?php echo $block; ?>" style="width: 100%;" type="text" size="30" maxlength="30" />
667
  </td>
668
  </tr>
669
 
671
  <td>
672
  Ad Slot ID
673
  </td>
674
+ <td style="padding-left: 7px;">
675
  <input id="adsense-ad-slot-id-<?php echo $block; ?>" style="width: 100%;" type="text" size="30" maxlength="30" />
676
  </td>
 
 
 
 
 
 
677
  </tr>
678
 
679
  <tr>
689
  <option value="<?php echo AI_ADSENSE_MATCHED_CONTENT; ?>"><?php echo AI_TEXT_MATCHED_CONTENT; ?></option>
690
  <option value="<?php echo AI_ADSENSE_AUTO; ?>"><?php echo AI_TEXT_AUTO; ?></option>
691
  </select>
692
+ <div class="adsense-size" style="float: right;">
693
+ Size
694
+ <select id="adsense-size-<?php echo $block; ?>">
695
+ <option value="<?php echo AI_ADSENSE_SIZE_FIXED; ?>" selected><?php echo AI_TEXT_FIXED; ?></option>
696
+ <option value="<?php echo AI_ADSENSE_SIZE_FIXED_BY_VIEWPORT; ?>"><?php echo AI_TEXT_FIXED_BY_VIEWPORT; ?></option>
697
+ <option value="<?php echo AI_ADSENSE_SIZE_RESPONSIVE; ?>"><?php echo AI_TEXT_RESPONSIVE; ?></option>
698
+ </select>
699
  </div>
700
  </td>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
701
  </tr>
702
 
703
  <tr>
711
  <option value="<?php echo AI_ADSENSE_AMP_BELOW_THE_FOLD; ?>"><?php echo AI_TEXT_BELOW_THE_FOLD; ?></option>
712
  </select>
713
  </td>
714
+ </tr>
715
+
716
+ <tr>
717
  <td>
718
  </td>
719
  <td>
720
  <?php if (defined ('AI_ADSENSE_API')) : ?>
721
  <?php if (!defined ('AI_ADSENSE_AUTHORIZATION_CODE')) : ?>
722
+ <button type="button" class='ai-button adsense-list' style="display: none; margin: 2px 0px 0px 7px;" title="Show AdSense ad units from your account">AdSense ad units</button>
723
  <?php endif; ?>
724
  <?php endif; ?>
725
  </td>
726
  </tr>
727
+ </table>
728
 
729
+ <table id="adsense-layout-<?php echo $block; ?>" class="ai-settings-table right">
730
+ <tr>
731
+ <td></td>
732
+ <td>
733
+ <input style="visibility: hidden;" type="text" size="1" maxlength="1" />
734
+ </td>
735
+ </tr>
736
+
737
+ <tr>
738
+ <td class="adsense-layout" style="padding-left: 7px;">
739
+ Layout
740
+ </td>
741
+ <td class="adsense-layout" style="width: 100%; padding-left: 7px;">
742
+ <input id="adsense-layout-<?php echo $block; ?>" style="width: 100%;" type="text" size="80" maxlength="100" />
743
+ </td>
744
+ </tr>
745
+
746
+ <tr>
747
+ <td class="adsense-layout" style="padding-left: 7px;">
748
+ Layout Key
749
+ </td>
750
+ <td class="adsense-layout" style="padding-left: 7px;">
751
+ <input id="adsense-layout-key-<?php echo $block; ?>" style="width: 100%;" type="text" size="80" maxlength="100" />
752
+ </td>
753
+ </tr>
754
+
755
+ <tr>
756
+ <td style="padding-left: 7px; padding-top: 1px; float: left;">
757
+ <span class="adsense-fixed-size ad-size">
758
+ <select class="adsense-ad-size fixed">
759
+ <option value="&nbsp;" selected></option>
760
+ <option value="300x250">300x250</option>
761
+ <option value="336x280">336x280</option>
762
+ <option value="728x90" >728x90</option>
763
+ <option value="300x600">300x600</option>
764
+ <option value="320x100">320x100</option>
765
+ <option value="468x60" >468x60</option>
766
+ <option value="234x60" >234x60</option>
767
+ <option value="125x125">125x125</option>
768
+ <option value="250x250">250x250</option>
769
+ <option value="200x200">200x200</option>
770
+ <option value="120x600">120x600</option>
771
+ <option value="160x600">160x600</option>
772
+ <option value="300x1050">300x1050</option>
773
+ <option value="320x50">320x50</option>
774
+ <option value="970x90">970x90</option>
775
+ <option value="970x250">970x250</option>
776
+ </select>
777
+ </span>
778
+ </td>
779
+ <td>
780
+ </td>
781
+ </tr>
782
+
783
+ </table>
784
+
785
+ <table id="adsense-viewports-<?php echo $block; ?>" class="ai-settings-table right" style="display: none; width: auto;">
786
+ <?php
787
+ for ($viewport = 1; $viewport <= AD_INSERTER_VIEWPORTS; $viewport ++) {
788
+ $viewport_name = get_viewport_name ($viewport);
789
+ $viewport_width = get_viewport_width ($viewport);
790
+ if ($viewport_name != '') { ?>
791
+ <tr class="adsense-viewport ad-size">
792
+ <td style="max-width: 210px; padding-left: 10px; overflow: hidden;">
793
+ <?php echo $viewport_name; ?>
794
+ </td>
795
+ <td style="padding-left: 7px;">
796
+ <select class="adsense-ad-size">
797
+ <option value="&nbsp;" selected></option>
798
+ <option value="300x250">300x250</option>
799
+ <option value="336x280">336x280</option>
800
+ <option value="728x90" >728x90</option>
801
+ <option value="300x600">300x600</option>
802
+ <option value="320x100">320x100</option>
803
+ <option value="468x60" >468x60</option>
804
+ <option value="234x60" >234x60</option>
805
+ <option value="125x125">125x125</option>
806
+ <option value="250x250">250x250</option>
807
+ <option value="200x200">200x200</option>
808
+ <option value="120x600">120x600</option>
809
+ <option value="160x600">160x600</option>
810
+ <option value="300x1050">300x1050</option>
811
+ <option value="320x50">320x50</option>
812
+ <option value="970x90">970x90</option>
813
+ <option value="970x250">970x250</option>
814
+ </select>
815
+ </span>
816
+ </td>
817
+ </tr>
818
+ <?php }
819
+ }
820
+ ?>
821
  </table>
822
+
823
  <div style="clear: both;"></div>
824
 
825
  </div>