Tracking Code Manager - Version 1.11.8

Version Description

Release Date - 2019-01-24

  • Tested with WordPress 5.0.3
  • Tested with WooCommerce 3.5.4
  • [Fixed] Deprecated functions on WooCommerce final thank you page
Download this release

Release Info

Developer IntellyWP
Plugin Icon 128x128 Tracking Code Manager
Version 1.11.8
Comparing to
See all releases

Code changes from version 1.5 to 1.11.8

Files changed (103) hide show
  1. assets/css/style.css +71 -16
  2. assets/deps/select2-3.5.2/.gitignore +2 -2
  3. assets/deps/select2-3.5.2/CONTRIBUTING.md +107 -107
  4. assets/deps/select2-3.5.2/LICENSE +18 -18
  5. assets/deps/select2-3.5.2/README.md +114 -114
  6. assets/deps/select2-3.5.2/bower.json +8 -8
  7. assets/deps/select2-3.5.2/component.json +66 -66
  8. assets/deps/select2-3.5.2/composer.json +29 -29
  9. assets/deps/select2-3.5.2/package.json +20 -20
  10. assets/deps/select2-3.5.2/release.sh +79 -79
  11. assets/deps/select2-3.5.2/select2-bootstrap.css +87 -87
  12. assets/deps/select2-3.5.2/select2.css +704 -704
  13. assets/deps/select2-3.5.2/select2.jquery.json +36 -36
  14. assets/deps/select2-3.5.2/select2.js +3541 -3541
  15. assets/deps/select2-3.5.2/select2.min.js +22 -22
  16. assets/deps/select2-3.5.2/select2_locale_ar.js +19 -19
  17. assets/deps/select2-3.5.2/select2_locale_az.js +20 -20
  18. assets/deps/select2-3.5.2/select2_locale_bg.js +20 -20
  19. assets/deps/select2-3.5.2/select2_locale_ca.js +19 -19
  20. assets/deps/select2-3.5.2/select2_locale_cs.js +51 -51
  21. assets/deps/select2-3.5.2/select2_locale_da.js +19 -19
  22. assets/deps/select2-3.5.2/select2_locale_de.js +17 -17
  23. assets/deps/select2-3.5.2/select2_locale_el.js +18 -18
  24. assets/deps/select2-3.5.2/select2_locale_en.js.template +20 -20
  25. assets/deps/select2-3.5.2/select2_locale_es.js +19 -19
  26. assets/deps/select2-3.5.2/select2_locale_et.js +19 -19
  27. assets/deps/select2-3.5.2/select2_locale_eu.js +45 -45
  28. assets/deps/select2-3.5.2/select2_locale_fa.js +21 -21
  29. assets/deps/select2-3.5.2/select2_locale_fi.js +30 -30
  30. assets/deps/select2-3.5.2/select2_locale_fr.js +18 -18
  31. assets/deps/select2-3.5.2/select2_locale_gl.js +45 -45
  32. assets/deps/select2-3.5.2/select2_locale_he.js +19 -19
  33. assets/deps/select2-3.5.2/select2_locale_hr.js +24 -24
  34. assets/deps/select2-3.5.2/select2_locale_hu.js +17 -17
  35. assets/deps/select2-3.5.2/select2_locale_id.js +19 -19
  36. assets/deps/select2-3.5.2/select2_locale_is.js +17 -17
  37. assets/deps/select2-3.5.2/select2_locale_it.js +16 -16
  38. assets/deps/select2-3.5.2/select2_locale_ja.js +17 -17
  39. assets/deps/select2-3.5.2/select2_locale_ka.js +19 -19
  40. assets/deps/select2-3.5.2/select2_locale_ko.js +19 -19
  41. assets/deps/select2-3.5.2/select2_locale_lt.js +26 -26
  42. assets/deps/select2-3.5.2/select2_locale_lv.js +19 -19
  43. assets/deps/select2-3.5.2/select2_locale_mk.js +18 -18
  44. assets/deps/select2-3.5.2/select2_locale_ms.js +19 -19
  45. assets/deps/select2-3.5.2/select2_locale_nb.js +22 -22
  46. assets/deps/select2-3.5.2/select2_locale_nl.js +17 -17
  47. assets/deps/select2-3.5.2/select2_locale_pl.js +54 -54
  48. assets/deps/select2-3.5.2/select2_locale_pt-BR.js +18 -18
  49. assets/deps/select2-3.5.2/select2_locale_pt-PT.js +17 -17
  50. assets/deps/select2-3.5.2/select2_locale_ro.js +17 -17
  51. assets/deps/select2-3.5.2/select2_locale_rs.js +19 -19
  52. assets/deps/select2-3.5.2/select2_locale_ru.js +23 -23
  53. assets/deps/select2-3.5.2/select2_locale_sk.js +50 -50
  54. assets/deps/select2-3.5.2/select2_locale_sv.js +19 -19
  55. assets/deps/select2-3.5.2/select2_locale_th.js +19 -19
  56. assets/deps/select2-3.5.2/select2_locale_tr.js +19 -19
  57. assets/deps/select2-3.5.2/select2_locale_ug-CN.js +16 -16
  58. assets/deps/select2-3.5.2/select2_locale_uk.js +25 -25
  59. assets/deps/select2-3.5.2/select2_locale_vi.js +20 -20
  60. assets/deps/select2-3.5.2/select2_locale_zh-CN.js +16 -16
  61. assets/deps/select2-3.5.2/select2_locale_zh-TW.js +16 -16
  62. assets/deps/starrr/starrr.css +7 -7
  63. assets/deps/starrr/starrr.js +123 -123
  64. assets/js/library.js +446 -0
  65. assets/js/plugin.js +104 -0
  66. assets/js/tcm-autocomplete.js +0 -49
  67. assets/landing/edd.png +0 -0
  68. assets/landing/mockup.png +0 -0
  69. assets/landing/screenshot-latest.png +0 -0
  70. assets/landing/tcmp-fb.png +0 -0
  71. assets/landing/woocommerce.png +0 -0
  72. assets/landing/wp-ecommerce.png +0 -0
  73. autoload.php +48 -0
  74. includes/actions.php +3 -69
  75. includes/admin/about.php +0 -30
  76. includes/admin/editor.php +336 -169
  77. includes/admin/feedback.php +0 -45
  78. includes/admin/manager.php +125 -74
  79. includes/admin/metabox.php +134 -99
  80. includes/admin/settings.php +32 -26
  81. includes/admin/whatsnew.php +89 -0
  82. includes/class-TCM-cron.php +0 -83
  83. includes/class-TCM-form.php +0 -298
  84. includes/class-TCM-language.php +0 -125
  85. includes/class-TCM-manager.php +0 -321
  86. includes/class-TCM-options.php +0 -278
  87. includes/class-TCM-utils.php +0 -209
  88. includes/classes/core/Manager.php +657 -0
  89. includes/classes/core/Singleton.php +36 -0
  90. includes/classes/domain/EcommercePurchase.php +16 -0
  91. includes/{class-TCM-check.php → classes/ui/Check.php} +8 -13
  92. includes/classes/ui/Form.php +486 -0
  93. includes/classes/ui/Tabs.php +294 -0
  94. includes/classes/utils/Cron.php +36 -0
  95. includes/classes/utils/Ecommerce.php +178 -0
  96. includes/classes/utils/Language.php +112 -0
  97. includes/{class-TCM-logger.php → classes/utils/Logger.php} +14 -12
  98. includes/classes/utils/MobileDetect.php +1435 -0
  99. includes/classes/utils/Options.php +430 -0
  100. includes/classes/utils/Plugin.php +237 -0
  101. includes/classes/utils/Properties.php +205 -0
  102. includes/{class-TCM-tracking.php → classes/utils/Tracking.php} +30 -55
  103. includes/classes/utils/Utils.php +2322 -0
assets/css/style.css CHANGED
@@ -1,4 +1,4 @@
1
- ._tcm {
2
  background-color: #efc439;
3
  border-radius: 2px;
4
  color: #fff;
@@ -9,7 +9,7 @@
9
  vertical-align: baseline;
10
  }
11
 
12
- .tcm-tag {
13
  display: inline-block;
14
  line-height: 13px;
15
  padding: 0 3px;
@@ -24,25 +24,25 @@
24
  border-radius: 2px;
25
  vertical-align: baseline;
26
  }
27
- .tcm-tag-free {
28
  /*background-color: #edb802;*/
29
  background-color: #16a765;
30
  }
31
- .tcm-tag-premium {
32
  /*background-color: #edb802;*/
33
  background-color: #4986e7;
34
  opacity: 0.7;
35
  filter: alpha(opacity=70);
36
  }
37
- .tcm-tag-premium a {
38
  color:white;
39
  text-decoration:none;
40
  }
41
- .tcm-button {
42
  margin-right:5px!important;
43
  }
44
 
45
- .tcm-textarea {
46
  font-family:"Courier New", Courier, mono;
47
  font-size:12px;
48
  color:#555;
@@ -51,36 +51,91 @@
51
  height:350px;
52
  }
53
 
54
- .tcm-form {
55
  float:left;
56
  padding:5px;
57
  }
58
- .tcm-form input, .tcm-form label {
59
  float:left;
60
  }
61
- .tcm-text {
62
  width: 400px;
63
  }
64
- .tcm-label {
65
  width: 150px;
66
  margin: 0px;
67
  background-color: transparent;
68
  }
69
- .tcm-label-disabled {
70
  /*color:#A8A8A8;*/
71
  opacity: 0.7;
72
  filter: alpha(opacity=70);
73
  }
74
- .tcm-checkbox {
75
  margin:0px;
76
  }
77
- .tcm-checkbox:disabled {
78
  background-color: #f8f8f8;
79
  }
80
- .tcm-select {
81
 
82
  }
83
- .tcm-form-newline {
84
  clear:both;
85
  margin-bottom:5px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  }
1
+ ._tcmp {
2
  background-color: #efc439;
3
  border-radius: 2px;
4
  color: #fff;
9
  vertical-align: baseline;
10
  }
11
 
12
+ .tcmp-tag {
13
  display: inline-block;
14
  line-height: 13px;
15
  padding: 0 3px;
24
  border-radius: 2px;
25
  vertical-align: baseline;
26
  }
27
+ .tcmp-tag-free {
28
  /*background-color: #edb802;*/
29
  background-color: #16a765;
30
  }
31
+ .tcmp-tag-premium {
32
  /*background-color: #edb802;*/
33
  background-color: #4986e7;
34
  opacity: 0.7;
35
  filter: alpha(opacity=70);
36
  }
37
+ .tcmp-tag-premium a {
38
  color:white;
39
  text-decoration:none;
40
  }
41
+ .tcmp-button {
42
  margin-right:5px!important;
43
  }
44
 
45
+ .tcmp-textarea {
46
  font-family:"Courier New", Courier, mono;
47
  font-size:12px;
48
  color:#555;
51
  height:350px;
52
  }
53
 
54
+ .tcmp-form {
55
  float:left;
56
  padding:5px;
57
  }
58
+ .tcmp-form input, .tcmp-form label {
59
  float:left;
60
  }
61
+ .tcmp-text {
62
  width: 400px;
63
  }
64
+ .tcmp-label {
65
  width: 150px;
66
  margin: 0px;
67
  background-color: transparent;
68
  }
69
+ .tcmp-label-disabled {
70
  /*color:#A8A8A8;*/
71
  opacity: 0.7;
72
  filter: alpha(opacity=70);
73
  }
74
+ .tcmp-checkbox {
75
  margin:0px;
76
  }
77
+ .tcmp-checkbox:disabled {
78
  background-color: #f8f8f8;
79
  }
80
+ .tcmp-select {
81
 
82
  }
83
+ .tcmp-form-newline {
84
  clear:both;
85
  margin-bottom:5px;
86
+ }
87
+
88
+ .tcmp-box-error {
89
+ background: #fff;
90
+ border-left: 4px solid #dd3d36;
91
+ margin: 5px 0 15px;
92
+ -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
93
+ box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
94
+ padding: 1px 12px;
95
+ }
96
+ .tcmp-box-warning {
97
+ background: #fff;
98
+ border-left: 4px solid #ffba00;
99
+ margin: 5px 0 15px;
100
+ -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
101
+ box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
102
+ padding: 1px 12px;
103
+ }
104
+ .tcmp-box-success {
105
+ background: #fff;
106
+ border-left: 4px solid #7ad03a;
107
+ margin: 5px 0 15px;
108
+ -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
109
+ box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
110
+ padding: 1px 12px;
111
+ }
112
+ .tcmp-box-info {
113
+ background: #fff;
114
+ border-left: 4px solid #00a0d2;
115
+ margin: 5px 0 15px;
116
+ -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
117
+ box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
118
+ padding: 1px 12px;
119
+ }
120
+
121
+ table thead {
122
+ background-color: #fafafa;
123
+ }
124
+ table tr td {
125
+ vertical-align: middle;
126
+ border-top: 1px solid #eeeeee;
127
+ }
128
+ table .odd {
129
+ background-color: white;
130
+ }
131
+ table .even {
132
+ background-color: #fafafa;
133
+ }
134
+ #tcmp-sidebar li {
135
+ margin: 0px!important;
136
+ margin-left: 20px!important;;
137
+ }
138
+ .tcmp-plugin-widget {
139
+ padding: 10px;
140
+ border: 2px dashed red;
141
  }
assets/deps/select2-3.5.2/.gitignore CHANGED
@@ -1,2 +1,2 @@
1
- .idea
2
-
1
+ .idea
2
+
assets/deps/select2-3.5.2/CONTRIBUTING.md CHANGED
@@ -1,107 +1,107 @@
1
- Contributing to Select2
2
- =======================
3
- Looking to contribute something to Select2? **Here's how you can help.**
4
-
5
- Please take a moment to review this document in order to make the contribution
6
- process easy and effective for everyone involved.
7
-
8
- Following these guidelines helps to communicate that you respect the time of
9
- the developers managing and developing this open source project. In return,
10
- they should reciprocate that respect in addressing your issue or assessing
11
- patches and features.
12
-
13
- Using the issue tracker
14
- -----------------------
15
- When [reporting bugs][reporting-bugs] or
16
- [requesting features][requesting-features], the
17
- [issue tracker on GitHub][issue-tracker] is the recommended channel to use.
18
-
19
- The issue tracker **is not** a place for support requests. The
20
- [mailing list][mailing-list] or [IRC channel][irc-channel] are better places to
21
- get help.
22
-
23
- Reporting bugs with Select2
24
- ---------------------------
25
- We really appreciate clear bug reports that _consistently_ show an issue
26
- _within Select2_.
27
-
28
- The ideal bug report follows these guidelines:
29
-
30
- 1. **Use the [GitHub issue search][issue-search]** — Check if the issue
31
- has already been reported.
32
- 2. **Check if the issue has been fixed** — Try to reproduce the problem
33
- using the code in the `master` branch.
34
- 3. **Isolate the problem** — Try to create an
35
- [isolated test case][isolated-case] that consistently reproduces the problem.
36
-
37
- Please try to be as detailed as possible in your bug report, especially if an
38
- isolated test case cannot be made. Some useful questions to include the answer
39
- to are:
40
-
41
- - What steps can be used to reproduce the issue?
42
- - What is the bug and what is the expected outcome?
43
- - What browser(s) and Operating System have you tested with?
44
- - Does the bug happen consistently across all tested browsers?
45
- - What version of jQuery are you using? And what version of Select2?
46
- - Are you using Select2 with other plugins?
47
-
48
- All of these questions will help people fix and identify any potential bugs.
49
-
50
- Requesting features in Select2
51
- ------------------------------
52
- Select2 is a large library that carries with it a lot of functionality. Because
53
- of this, many feature requests will not be implemented in the core library.
54
-
55
- Before starting work on a major feature for Select2, **contact the
56
- [community][community] first** or you may risk spending a considerable amount of
57
- time on something which the project developers are not interested in bringing
58
- into the project.
59
-
60
- ### Select2 4.0
61
-
62
- Many feature requests will be closed off until 4.0, where Select2 plans to adopt
63
- a more flexible API. If you are interested in helping with the development of
64
- the next major Select2 release, please send a message to the
65
- [mailing list][mailing-list] or [irc channel][irc-channel] for more information.
66
-
67
- Triaging issues and pull requests
68
- ---------------------------------
69
- Anyone can help the project maintainers triage issues and review pull requests.
70
-
71
- ### Handling new issues
72
-
73
- Select2 regularly receives new issues which need to be tested and organized.
74
-
75
- When a new issue that comes in that is similar to another existing issue, it
76
- should be checked to make sure it is not a duplicate. Duplicates issues should
77
- be marked by replying to the issue with "Duplicate of #[issue number]" where
78
- `[issue number]` is the url or issue number for the existing issue. This will
79
- allow the project maintainers to quickly close off additional issues and keep
80
- the discussion focused within a single issue.
81
-
82
- If you can test issues that are reported to Select2 that contain test cases and
83
- confirm under what conditions bugs happen, that will allow others to identify
84
- what causes a bug quicker.
85
-
86
- ### Reviewing pull requests
87
-
88
- It is very common for pull requests to be opened for issues that contain a clear
89
- solution to the problem. These pull requests should be rigorously reviewed by
90
- the community before being accepted. If you are not sure about a piece of
91
- submitted code, or know of a better way to do something, do not hesitate to make
92
- a comment on the pull request.
93
-
94
- It should also be made clear that **all code contributed to Select** must be
95
- licensable under the [Apache 2 or GPL 2 licenses][licensing]. Code that cannot
96
- be released under either of these licenses **cannot be accepted** into the
97
- project.
98
-
99
- [community]: https://github.com/ivaynberg/select2#community
100
- [reporting-bugs]: #reporting-bugs-with-select2
101
- [requesting-features]: #requesting-features-in-select2
102
- [issue-tracker]: https://github.com/ivaynberg/select2/issues
103
- [mailing-list]: https://github.com/ivaynberg/select2#mailing-list
104
- [irc-channel]: https://github.com/ivaynberg/select2#irc-channel
105
- [issue-search]: https://github.com/ivaynberg/select2/search?q=&type=Issues
106
- [isolated-case]: http://css-tricks.com/6263-reduced-test-cases/
107
- [licensing]: https://github.com/ivaynberg/select2#copyright-and-license
1
+ Contributing to Select2
2
+ =======================
3
+ Looking to contribute something to Select2? **Here's how you can help.**
4
+
5
+ Please take a moment to review this document in order to make the contribution
6
+ process easy and effective for everyone involved.
7
+
8
+ Following these guidelines helps to communicate that you respect the time of
9
+ the developers managing and developing this open source project. In return,
10
+ they should reciprocate that respect in addressing your issue or assessing
11
+ patches and features.
12
+
13
+ Using the issue tracker
14
+ -----------------------
15
+ When [reporting bugs][reporting-bugs] or
16
+ [requesting features][requesting-features], the
17
+ [issue tracker on GitHub][issue-tracker] is the recommended channel to use.
18
+
19
+ The issue tracker **is not** a place for support requests. The
20
+ [mailing list][mailing-list] or [IRC channel][irc-channel] are better places to
21
+ get help.
22
+
23
+ Reporting bugs with Select2
24
+ ---------------------------
25
+ We really appreciate clear bug reports that _consistently_ show an issue
26
+ _within Select2_.
27
+
28
+ The ideal bug report follows these guidelines:
29
+
30
+ 1. **Use the [GitHub issue search][issue-search]** — Check if the issue
31
+ has already been reported.
32
+ 2. **Check if the issue has been fixed** — Try to reproduce the problem
33
+ using the code in the `master` branch.
34
+ 3. **Isolate the problem** — Try to create an
35
+ [isolated test case][isolated-case] that consistently reproduces the problem.
36
+
37
+ Please try to be as detailed as possible in your bug report, especially if an
38
+ isolated test case cannot be made. Some useful questions to include the answer
39
+ to are:
40
+
41
+ - What steps can be used to reproduce the issue?
42
+ - What is the bug and what is the expected outcome?
43
+ - What browser(s) and Operating System have you tested with?
44
+ - Does the bug happen consistently across all tested browsers?
45
+ - What version of jQuery are you using? And what version of Select2?
46
+ - Are you using Select2 with other plugins?
47
+
48
+ All of these questions will help people fix and identify any potential bugs.
49
+
50
+ Requesting features in Select2
51
+ ------------------------------
52
+ Select2 is a large library that carries with it a lot of functionality. Because
53
+ of this, many feature requests will not be implemented in the core library.
54
+
55
+ Before starting work on a major feature for Select2, **contact the
56
+ [community][community] first** or you may risk spending a considerable amount of
57
+ time on something which the project developers are not interested in bringing
58
+ into the project.
59
+
60
+ ### Select2 4.0
61
+
62
+ Many feature requests will be closed off until 4.0, where Select2 plans to adopt
63
+ a more flexible API. If you are interested in helping with the development of
64
+ the next major Select2 release, please send a message to the
65
+ [mailing list][mailing-list] or [irc channel][irc-channel] for more information.
66
+
67
+ Triaging issues and pull requests
68
+ ---------------------------------
69
+ Anyone can help the project maintainers triage issues and review pull requests.
70
+
71
+ ### Handling new issues
72
+
73
+ Select2 regularly receives new issues which need to be tested and organized.
74
+
75
+ When a new issue that comes in that is similar to another existing issue, it
76
+ should be checked to make sure it is not a duplicate. Duplicates issues should
77
+ be marked by replying to the issue with "Duplicate of #[issue number]" where
78
+ `[issue number]` is the url or issue number for the existing issue. This will
79
+ allow the project maintainers to quickly close off additional issues and keep
80
+ the discussion focused within a single issue.
81
+
82
+ If you can test issues that are reported to Select2 that contain test cases and
83
+ confirm under what conditions bugs happen, that will allow others to identify
84
+ what causes a bug quicker.
85
+
86
+ ### Reviewing pull requests
87
+
88
+ It is very common for pull requests to be opened for issues that contain a clear
89
+ solution to the problem. These pull requests should be rigorously reviewed by
90
+ the community before being accepted. If you are not sure about a piece of
91
+ submitted code, or know of a better way to do something, do not hesitate to make
92
+ a comment on the pull request.
93
+
94
+ It should also be made clear that **all code contributed to Select** must be
95
+ licensable under the [Apache 2 or GPL 2 licenses][licensing]. Code that cannot
96
+ be released under either of these licenses **cannot be accepted** into the
97
+ project.
98
+
99
+ [community]: https://github.com/ivaynberg/select2#community
100
+ [reporting-bugs]: #reporting-bugs-with-select2
101
+ [requesting-features]: #requesting-features-in-select2
102
+ [issue-tracker]: https://github.com/ivaynberg/select2/issues
103
+ [mailing-list]: https://github.com/ivaynberg/select2#mailing-list
104
+ [irc-channel]: https://github.com/ivaynberg/select2#irc-channel
105
+ [issue-search]: https://github.com/ivaynberg/select2/search?q=&type=Issues
106
+ [isolated-case]: http://css-tricks.com/6263-reduced-test-cases/
107
+ [licensing]: https://github.com/ivaynberg/select2#copyright-and-license
assets/deps/select2-3.5.2/LICENSE CHANGED
@@ -1,18 +1,18 @@
1
- Copyright 2014 Igor Vaynberg
2
-
3
- Version: @@ver@@ Timestamp: @@timestamp@@
4
-
5
- This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
6
- General Public License version 2 (the "GPL License"). You may choose either license to govern your
7
- use of this software only upon the condition that you accept all of the terms of either the Apache
8
- License or the GPL License.
9
-
10
- You may obtain a copy of the Apache License and the GPL License at:
11
-
12
- http://www.apache.org/licenses/LICENSE-2.0
13
- http://www.gnu.org/licenses/gpl-2.0.html
14
-
15
- Unless required by applicable law or agreed to in writing, software distributed under the Apache License
16
- or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17
- either express or implied. See the Apache License and the GPL License for the specific language governing
18
- permissions and limitations under the Apache License and the GPL License.
1
+ Copyright 2014 Igor Vaynberg
2
+
3
+ Version: @@ver@@ Timestamp: @@timestamp@@
4
+
5
+ This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
6
+ General Public License version 2 (the "GPL License"). You may choose either license to govern your
7
+ use of this software only upon the condition that you accept all of the terms of either the Apache
8
+ License or the GPL License.
9
+
10
+ You may obtain a copy of the Apache License and the GPL License at:
11
+
12
+ http://www.apache.org/licenses/LICENSE-2.0
13
+ http://www.gnu.org/licenses/gpl-2.0.html
14
+
15
+ Unless required by applicable law or agreed to in writing, software distributed under the Apache License
16
+ or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17
+ either express or implied. See the Apache License and the GPL License for the specific language governing
18
+ permissions and limitations under the Apache License and the GPL License.
assets/deps/select2-3.5.2/README.md CHANGED
@@ -1,114 +1,114 @@
1
- Select2
2
- =======
3
-
4
- Select2 is a jQuery-based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.
5
-
6
- To get started, checkout examples and documentation at http://ivaynberg.github.com/select2
7
-
8
- Use cases
9
- ---------
10
-
11
- * Enhancing native selects with search.
12
- * Enhancing native selects with a better multi-select interface.
13
- * Loading data from JavaScript: easily load items via ajax and have them searchable.
14
- * Nesting optgroups: native selects only support one level of nested. Select2 does not have this restriction.
15
- * Tagging: ability to add new items on the fly.
16
- * Working with large, remote datasets: ability to partially load a dataset based on the search term.
17
- * Paging of large datasets: easy support for loading more pages when the results are scrolled to the end.
18
- * Templating: support for custom rendering of results and selections.
19
-
20
- Browser compatibility
21
- ---------------------
22
- * IE 8+
23
- * Chrome 8+
24
- * Firefox 10+
25
- * Safari 3+
26
- * Opera 10.6+
27
-
28
- Usage
29
- -----
30
- You can source Select2 directly from a CDN like [JSDliver](http://www.jsdelivr.com/#!select2) or [CDNJS](http://www.cdnjs.com/libraries/select2), [download it from this GitHub repo](https://github.com/ivaynberg/select2/tags), or use one of the integrations below.
31
-
32
- Integrations
33
- ------------
34
-
35
- * [Wicket-Select2](https://github.com/ivaynberg/wicket-select2) (Java / [Apache Wicket](http://wicket.apache.org))
36
- * [select2-rails](https://github.com/argerim/select2-rails) (Ruby on Rails)
37
- * [AngularUI](http://angular-ui.github.io/#ui-select) ([AngularJS](https://angularjs.org/))
38
- * [Django](https://github.com/applegrew/django-select2)
39
- * [Symfony](https://github.com/19Gerhard85/sfSelect2WidgetsPlugin)
40
- * [Symfony2](https://github.com/avocode/FormExtensions)
41
- * [Bootstrap 2](https://github.com/t0m/select2-bootstrap-css) and [Bootstrap 3](https://github.com/t0m/select2-bootstrap-css/tree/bootstrap3) (CSS skins)
42
- * [Meteor](https://github.com/nate-strauser/meteor-select2) (modern reactive JavaScript framework; + [Bootstrap 3 skin](https://github.com/esperadomedia/meteor-select2-bootstrap3-css/))
43
- * [Meteor](https://jquery-select2.meteor.com)
44
- * [Yii 2.x](http://demos.krajee.com/widgets#select2)
45
- * [Yii 1.x](https://github.com/tonybolzan/yii-select2)
46
- * [AtmosphereJS](https://atmospherejs.com/package/jquery-select2)
47
-
48
- ### Example Integrations
49
-
50
- * [Knockout.js](https://github.com/ivaynberg/select2/wiki/Knockout.js-Integration)
51
- * [Socket.IO](https://github.com/ivaynberg/select2/wiki/Socket.IO-Integration)
52
- * [PHP](https://github.com/ivaynberg/select2/wiki/PHP-Example)
53
- * [.Net MVC] (https://github.com/ivaynberg/select2/wiki/.Net-MVC-Example)
54
-
55
- Internationalization (i18n)
56
- ---------------------------
57
-
58
- Select2 supports multiple languages by simply including the right language JS
59
- file (`select2_locale_it.js`, `select2_locale_nl.js`, etc.) after `select2.js`.
60
-
61
- Missing a language? Just copy `select2_locale_en.js.template`, translate
62
- it, and make a pull request back to Select2 here on GitHub.
63
-
64
- Documentation
65
- -------------
66
-
67
- The documentation for Select2 is available [through GitHub Pages](https://ivaynberg.github.io/select2/) and is located within this repository in the [`gh-pages` branch](https://github.com/ivaynberg/select2/tree/gh-pages).
68
-
69
- Community
70
- ---------
71
-
72
- ### Bug tracker
73
-
74
- Have a bug? Please create an issue here on GitHub!
75
-
76
- https://github.com/ivaynberg/select2/issues
77
-
78
- ### Mailing list
79
-
80
- Have a question? Ask on our mailing list!
81
-
82
- select2@googlegroups.com
83
-
84
- https://groups.google.com/d/forum/select2
85
-
86
- ### IRC channel
87
-
88
- Need help implementing Select2 in your project? Ask in our IRC channel!
89
-
90
- **Network:** [Freenode](https://freenode.net/) (`chat.freenode.net`)
91
-
92
- **Channel:** `#select2`
93
-
94
- **Web access:** https://webchat.freenode.net/?channels=select2
95
-
96
- Copyright and license
97
- ---------------------
98
-
99
- Copyright 2012 Igor Vaynberg
100
-
101
- This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
102
- General Public License version 2 (the "GPL License"). You may choose either license to govern your
103
- use of this software only upon the condition that you accept all of the terms of either the Apache
104
- License or the GPL License.
105
-
106
- You may obtain a copy of the Apache License and the GPL License in the LICENSE file, or at:
107
-
108
- http://www.apache.org/licenses/LICENSE-2.0
109
- http://www.gnu.org/licenses/gpl-2.0.html
110
-
111
- Unless required by applicable law or agreed to in writing, software distributed under the Apache License
112
- or the GPL License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
113
- either express or implied. See the Apache License and the GPL License for the specific language governing
114
- permissions and limitations under the Apache License and the GPL License.
1
+ Select2
2
+ =======
3
+
4
+ Select2 is a jQuery-based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.
5
+
6
+ To get started, checkout examples and documentation at http://ivaynberg.github.com/select2
7
+
8
+ Use cases
9
+ ---------
10
+
11
+ * Enhancing native selects with search.
12
+ * Enhancing native selects with a better multi-select interface.
13
+ * Loading data from JavaScript: easily load items via ajax and have them searchable.
14
+ * Nesting optgroups: native selects only support one level of nested. Select2 does not have this restriction.
15
+ * Tagging: ability to add new items on the fly.
16
+ * Working with large, remote datasets: ability to partially load a dataset based on the search term.
17
+ * Paging of large datasets: easy support for loading more pages when the results are scrolled to the end.
18
+ * Templating: support for custom rendering of results and selections.
19
+
20
+ Browser compatibility
21
+ ---------------------
22
+ * IE 8+
23
+ * Chrome 8+
24
+ * Firefox 10+
25
+ * Safari 3+
26
+ * Opera 10.6+
27
+
28
+ Usage
29
+ -----
30
+ You can source Select2 directly from a CDN like [JSDliver](http://www.jsdelivr.com/#!select2) or [CDNJS](http://www.cdnjs.com/libraries/select2), [download it from this GitHub repo](https://github.com/ivaynberg/select2/tags), or use one of the integrations below.
31
+
32
+ Integrations
33
+ ------------
34
+
35
+ * [Wicket-Select2](https://github.com/ivaynberg/wicket-select2) (Java / [Apache Wicket](http://wicket.apache.org))
36
+ * [select2-rails](https://github.com/argerim/select2-rails) (Ruby on Rails)
37
+ * [AngularUI](http://angular-ui.github.io/#ui-select) ([AngularJS](https://angularjs.org/))
38
+ * [Django](https://github.com/applegrew/django-select2)
39
+ * [Symfony](https://github.com/19Gerhard85/sfSelect2WidgetsPlugin)
40
+ * [Symfony2](https://github.com/avocode/FormExtensions)
41
+ * [Bootstrap 2](https://github.com/t0m/select2-bootstrap-css) and [Bootstrap 3](https://github.com/t0m/select2-bootstrap-css/tree/bootstrap3) (CSS skins)
42
+ * [Meteor](https://github.com/nate-strauser/meteor-select2) (modern reactive JavaScript framework; + [Bootstrap 3 skin](https://github.com/esperadomedia/meteor-select2-bootstrap3-css/))
43
+ * [Meteor](https://jquery-select2.meteor.com)
44
+ * [Yii 2.x](http://demos.krajee.com/widgets#select2)
45
+ * [Yii 1.x](https://github.com/tonybolzan/yii-select2)
46
+ * [AtmosphereJS](https://atmospherejs.com/package/jquery-select2)
47
+
48
+ ### Example Integrations
49
+
50
+ * [Knockout.js](https://github.com/ivaynberg/select2/wiki/Knockout.js-Integration)
51
+ * [Socket.IO](https://github.com/ivaynberg/select2/wiki/Socket.IO-Integration)
52
+ * [PHP](https://github.com/ivaynberg/select2/wiki/PHP-Example)
53
+ * [.Net MVC] (https://github.com/ivaynberg/select2/wiki/.Net-MVC-Example)
54
+
55
+ Internationalization (i18n)
56
+ ---------------------------
57
+
58
+ Select2 supports multiple languages by simply including the right language JS
59
+ file (`select2_locale_it.js`, `select2_locale_nl.js`, etc.) after `select2.js`.
60
+
61
+ Missing a language? Just copy `select2_locale_en.js.template`, translate
62
+ it, and make a pull request back to Select2 here on GitHub.
63
+
64
+ Documentation
65
+ -------------
66
+
67
+ The documentation for Select2 is available [through GitHub Pages](https://ivaynberg.github.io/select2/) and is located within this repository in the [`gh-pages` branch](https://github.com/ivaynberg/select2/tree/gh-pages).
68
+
69
+ Community
70
+ ---------
71
+
72
+ ### Bug tracker
73
+
74
+ Have a bug? Please create an issue here on GitHub!
75
+
76
+ https://github.com/ivaynberg/select2/issues
77
+
78
+ ### Mailing list
79
+
80
+ Have a question? Ask on our mailing list!
81
+
82
+ select2@googlegroups.com
83
+
84
+ https://groups.google.com/d/forum/select2
85
+
86
+ ### IRC channel
87
+
88
+ Need help implementing Select2 in your project? Ask in our IRC channel!
89
+
90
+ **Network:** [Freenode](https://freenode.net/) (`chat.freenode.net`)
91
+
92
+ **Channel:** `#select2`
93
+
94
+ **Web access:** https://webchat.freenode.net/?channels=select2
95
+
96
+ Copyright and license
97
+ ---------------------
98
+
99
+ Copyright 2012 Igor Vaynberg
100
+
101
+ This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
102
+ General Public License version 2 (the "GPL License"). You may choose either license to govern your
103
+ use of this software only upon the condition that you accept all of the terms of either the Apache
104
+ License or the GPL License.
105
+
106
+ You may obtain a copy of the Apache License and the GPL License in the LICENSE file, or at:
107
+
108
+ http://www.apache.org/licenses/LICENSE-2.0
109
+ http://www.gnu.org/licenses/gpl-2.0.html
110
+
111
+ Unless required by applicable law or agreed to in writing, software distributed under the Apache License
112
+ or the GPL License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
113
+ either express or implied. See the Apache License and the GPL License for the specific language governing
114
+ permissions and limitations under the Apache License and the GPL License.
assets/deps/select2-3.5.2/bower.json CHANGED
@@ -1,8 +1,8 @@
1
- {
2
- "name": "select2",
3
- "version": "3.5.2",
4
- "main": ["select2.js", "select2.css", "select2.png", "select2x2.png", "select2-spinner.gif"],
5
- "dependencies": {
6
- "jquery": ">= 1.7.1"
7
- }
8
- }
1
+ {
2
+ "name": "select2",
3
+ "version": "3.5.2",
4
+ "main": ["select2.js", "select2.css", "select2.png", "select2x2.png", "select2-spinner.gif"],
5
+ "dependencies": {
6
+ "jquery": ">= 1.7.1"
7
+ }
8
+ }
assets/deps/select2-3.5.2/component.json CHANGED
@@ -1,66 +1,66 @@
1
- {
2
- "name": "select2",
3
- "repo": "ivaynberg/select2",
4
- "description": "Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.",
5
- "version": "3.5.2",
6
- "demo": "http://ivaynberg.github.io/select2/",
7
- "keywords": [
8
- "jquery"
9
- ],
10
- "main": "select2.js",
11
- "styles": [
12
- "select2.css",
13
- "select2-bootstrap.css"
14
- ],
15
- "scripts": [
16
- "select2.js",
17
- "select2_locale_ar.js",
18
- "select2_locale_bg.js",
19
- "select2_locale_ca.js",
20
- "select2_locale_cs.js",
21
- "select2_locale_da.js",
22
- "select2_locale_de.js",
23
- "select2_locale_el.js",
24
- "select2_locale_es.js",
25
- "select2_locale_et.js",
26
- "select2_locale_eu.js",
27
- "select2_locale_fa.js",
28
- "select2_locale_fi.js",
29
- "select2_locale_fr.js",
30
- "select2_locale_gl.js",
31
- "select2_locale_he.js",
32
- "select2_locale_hr.js",
33
- "select2_locale_hu.js",
34
- "select2_locale_id.js",
35
- "select2_locale_is.js",
36
- "select2_locale_it.js",
37
- "select2_locale_ja.js",
38
- "select2_locale_ka.js",
39
- "select2_locale_ko.js",
40
- "select2_locale_lt.js",
41
- "select2_locale_lv.js",
42
- "select2_locale_mk.js",
43
- "select2_locale_ms.js",
44
- "select2_locale_nl.js",
45
- "select2_locale_no.js",
46
- "select2_locale_pl.js",
47
- "select2_locale_pt-BR.js",
48
- "select2_locale_pt-PT.js",
49
- "select2_locale_ro.js",
50
- "select2_locale_ru.js",
51
- "select2_locale_sk.js",
52
- "select2_locale_sv.js",
53
- "select2_locale_th.js",
54
- "select2_locale_tr.js",
55
- "select2_locale_uk.js",
56
- "select2_locale_vi.js",
57
- "select2_locale_zh-CN.js",
58
- "select2_locale_zh-TW.js"
59
- ],
60
- "images": [
61
- "select2-spinner.gif",
62
- "select2.png",
63
- "select2x2.png"
64
- ],
65
- "license": "MIT"
66
- }
1
+ {
2
+ "name": "select2",
3
+ "repo": "ivaynberg/select2",
4
+ "description": "Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.",
5
+ "version": "3.5.2",
6
+ "demo": "http://ivaynberg.github.io/select2/",
7
+ "keywords": [
8
+ "jquery"
9
+ ],
10
+ "main": "select2.js",
11
+ "styles": [
12
+ "select2.css",
13
+ "select2-bootstrap.css"
14
+ ],
15
+ "scripts": [
16
+ "select2.js",
17
+ "select2_locale_ar.js",
18
+ "select2_locale_bg.js",
19
+ "select2_locale_ca.js",
20
+ "select2_locale_cs.js",
21
+ "select2_locale_da.js",
22
+ "select2_locale_de.js",
23
+ "select2_locale_el.js",
24
+ "select2_locale_es.js",
25
+ "select2_locale_et.js",
26
+ "select2_locale_eu.js",
27
+ "select2_locale_fa.js",
28
+ "select2_locale_fi.js",
29
+ "select2_locale_fr.js",
30
+ "select2_locale_gl.js",
31
+ "select2_locale_he.js",
32
+ "select2_locale_hr.js",
33
+ "select2_locale_hu.js",
34
+ "select2_locale_id.js",
35
+ "select2_locale_is.js",
36
+ "select2_locale_it.js",
37
+ "select2_locale_ja.js",
38
+ "select2_locale_ka.js",
39
+ "select2_locale_ko.js",
40
+ "select2_locale_lt.js",
41
+ "select2_locale_lv.js",
42
+ "select2_locale_mk.js",
43
+ "select2_locale_ms.js",
44
+ "select2_locale_nl.js",
45
+ "select2_locale_no.js",
46
+ "select2_locale_pl.js",
47
+ "select2_locale_pt-BR.js",
48
+ "select2_locale_pt-PT.js",
49
+ "select2_locale_ro.js",
50
+ "select2_locale_ru.js",
51
+ "select2_locale_sk.js",
52
+ "select2_locale_sv.js",
53
+ "select2_locale_th.js",
54
+ "select2_locale_tr.js",
55
+ "select2_locale_uk.js",
56
+ "select2_locale_vi.js",
57
+ "select2_locale_zh-CN.js",
58
+ "select2_locale_zh-TW.js"
59
+ ],
60
+ "images": [
61
+ "select2-spinner.gif",
62
+ "select2.png",
63
+ "select2x2.png"
64
+ ],
65
+ "license": "MIT"
66
+ }
assets/deps/select2-3.5.2/composer.json CHANGED
@@ -1,29 +1,29 @@
1
- {
2
- "name":
3
- "ivaynberg/select2",
4
- "description": "Select2 is a jQuery based replacement for select boxes.",
5
- "version": "3.5.2",
6
- "type": "component",
7
- "homepage": "http://ivaynberg.github.io/select2/",
8
- "license": "Apache-2.0",
9
- "require": {
10
- "robloach/component-installer": "*",
11
- "components/jquery": ">=1.7.1"
12
- },
13
- "extra": {
14
- "component": {
15
- "scripts": [
16
- "select2.js"
17
- ],
18
- "files": [
19
- "select2.js",
20
- "select2_locale_*.js",
21
- "select2.css",
22
- "select2-bootstrap.css",
23
- "select2-spinner.gif",
24
- "select2.png",
25
- "select2x2.png"
26
- ]
27
- }
28
- }
29
- }
1
+ {
2
+ "name":
3
+ "ivaynberg/select2",
4
+ "description": "Select2 is a jQuery based replacement for select boxes.",
5
+ "version": "3.5.2",
6
+ "type": "component",
7
+ "homepage": "http://ivaynberg.github.io/select2/",
8
+ "license": "Apache-2.0",
9
+ "require": {
10
+ "robloach/component-installer": "*",
11
+ "components/jquery": ">=1.7.1"
12
+ },
13
+ "extra": {
14
+ "component": {
15
+ "scripts": [
16
+ "select2.js"
17
+ ],
18
+ "files": [
19
+ "select2.js",
20
+ "select2_locale_*.js",
21
+ "select2.css",
22
+ "select2-bootstrap.css",
23
+ "select2-spinner.gif",
24
+ "select2.png",
25
+ "select2x2.png"
26
+ ]
27
+ }
28
+ }
29
+ }
assets/deps/select2-3.5.2/package.json CHANGED
@@ -1,20 +1,20 @@
1
- {
2
- "name" : "Select2",
3
- "description": "Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.",
4
- "homepage": "http://ivaynberg.github.io/select2",
5
- "author": "Igor Vaynberg",
6
- "repository": {"type": "git", "url": "git://github.com/ivaynberg/select2.git"},
7
- "main": "select2.js",
8
- "version": "3.5.2",
9
- "jspm": {
10
- "main": "select2",
11
- "files": ["select2.js", "select2.png", "select2.css", "select2-spinner.gif"],
12
- "shim": {
13
- "select2": {
14
- "imports": ["jquery", "./select2.css!"],
15
- "exports": "$"
16
- }
17
- },
18
- "buildConfig": { "uglify": true }
19
- }
20
- }
1
+ {
2
+ "name" : "Select2",
3
+ "description": "Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.",
4
+ "homepage": "http://ivaynberg.github.io/select2",
5
+ "author": "Igor Vaynberg",
6
+ "repository": {"type": "git", "url": "git://github.com/ivaynberg/select2.git"},
7
+ "main": "select2.js",
8
+ "version": "3.5.2",
9
+ "jspm": {
10
+ "main": "select2",
11
+ "files": ["select2.js", "select2.png", "select2.css", "select2-spinner.gif"],
12
+ "shim": {
13
+ "select2": {
14
+ "imports": ["jquery", "./select2.css!"],
15
+ "exports": "$"
16
+ }
17
+ },
18
+ "buildConfig": { "uglify": true }
19
+ }
20
+ }
assets/deps/select2-3.5.2/release.sh CHANGED
@@ -1,79 +1,79 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- echo -n "Enter the version for this release: "
5
-
6
- read ver
7
-
8
- if [ ! $ver ]; then
9
- echo "Invalid version."
10
- exit
11
- fi
12
-
13
- name="select2"
14
- js="$name.js"
15
- mini="$name.min.js"
16
- css="$name.css"
17
- release="$name-$ver"
18
- tag="$ver"
19
- branch="build-$ver"
20
- curbranch=`git branch | grep "*" | sed "s/* //"`
21
- timestamp=$(date)
22
- tokens="s/@@ver@@/$ver/g;s/\@@timestamp@@/$timestamp/g"
23
- remote="origin"
24
-
25
- echo "Pulling from origin"
26
-
27
- git pull
28
-
29
- echo "Updating Version Identifiers"
30
-
31
- sed -E -e "s/\"version\": \"([0-9\.]+)\",/\"version\": \"$ver\",/g" -i -- bower.json select2.jquery.json component.json composer.json package.json
32
-
33
- git add bower.json
34
- git add select2.jquery.json
35
- git add component.json
36
- git add composer.json
37
- git add package.json
38
-
39
- git commit -m "modified version identifiers in descriptors for release $ver"
40
- git push
41
-
42
- git branch "$branch"
43
- git checkout "$branch"
44
-
45
- echo "Tokenizing..."
46
-
47
- find . -name "$js" | xargs -I{} sed -e "$tokens" -i -- {}
48
- find . -name "$css" | xargs -I{} sed -e "$tokens" -i -- {}
49
-
50
- sed -e "s/latest/$ver/g" -i -- bower.json
51
-
52
- git add "$js"
53
- git add "$css"
54
-
55
- echo "Minifying..."
56
-
57
- echo "/*" > "$mini"
58
- cat LICENSE | sed "$tokens" >> "$mini"
59
- echo "*/" >> "$mini"
60
-
61
- curl -s \
62
- --data-urlencode "js_code@$js" \
63
- http://marijnhaverbeke.nl/uglifyjs \
64
- >> "$mini"
65
-
66
- git add "$mini"
67
-
68
- git commit -m "release $ver"
69
-
70
- echo "Tagging..."
71
- git tag -a "$tag" -m "tagged version $ver"
72
- git push "$remote" --tags
73
-
74
- echo "Cleaning Up..."
75
-
76
- git checkout "$curbranch"
77
- git branch -D "$branch"
78
-
79
- echo "Done"
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ echo -n "Enter the version for this release: "
5
+
6
+ read ver
7
+
8
+ if [ ! $ver ]; then
9
+ echo "Invalid version."
10
+ exit
11
+ fi
12
+
13
+ name="select2"
14
+ js="$name.js"
15
+ mini="$name.min.js"
16
+ css="$name.css"
17
+ release="$name-$ver"
18
+ tag="$ver"
19
+ branch="build-$ver"
20
+ curbranch=`git branch | grep "*" | sed "s/* //"`
21
+ timestamp=$(date)
22
+ tokens="s/@@ver@@/$ver/g;s/\@@timestamp@@/$timestamp/g"
23
+ remote="origin"
24
+
25
+ echo "Pulling from origin"
26
+
27
+ git pull
28
+
29
+ echo "Updating Version Identifiers"
30
+
31
+ sed -E -e "s/\"version\": \"([0-9\.]+)\",/\"version\": \"$ver\",/g" -i -- bower.json select2.jquery.json component.json composer.json package.json
32
+
33
+ git add bower.json
34
+ git add select2.jquery.json
35
+ git add component.json
36
+ git add composer.json
37
+ git add package.json
38
+
39
+ git commit -m "modified version identifiers in descriptors for release $ver"
40
+ git push
41
+
42
+ git branch "$branch"
43
+ git checkout "$branch"
44
+
45
+ echo "Tokenizing..."
46
+
47
+ find . -name "$js" | xargs -I{} sed -e "$tokens" -i -- {}
48
+ find . -name "$css" | xargs -I{} sed -e "$tokens" -i -- {}
49
+
50
+ sed -e "s/latest/$ver/g" -i -- bower.json
51
+
52
+ git add "$js"
53
+ git add "$css"
54
+
55
+ echo "Minifying..."
56
+
57
+ echo "/*" > "$mini"
58
+ cat LICENSE | sed "$tokens" >> "$mini"
59
+ echo "*/" >> "$mini"
60
+
61
+ curl -s \
62
+ --data-urlencode "js_code@$js" \
63
+ http://marijnhaverbeke.nl/uglifyjs \
64
+ >> "$mini"
65
+
66
+ git add "$mini"
67
+
68
+ git commit -m "release $ver"
69
+
70
+ echo "Tagging..."
71
+ git tag -a "$tag" -m "tagged version $ver"
72
+ git push "$remote" --tags
73
+
74
+ echo "Cleaning Up..."
75
+
76
+ git checkout "$curbranch"
77
+ git branch -D "$branch"
78
+
79
+ echo "Done"
assets/deps/select2-3.5.2/select2-bootstrap.css CHANGED
@@ -1,87 +1,87 @@
1
- .form-control .select2-choice {
2
- border: 0;
3
- border-radius: 2px;
4
- }
5
-
6
- .form-control .select2-choice .select2-arrow {
7
- border-radius: 0 2px 2px 0;
8
- }
9
-
10
- .form-control.select2-container {
11
- height: auto !important;
12
- padding: 0;
13
- }
14
-
15
- .form-control.select2-container.select2-dropdown-open {
16
- border-color: #5897FB;
17
- border-radius: 3px 3px 0 0;
18
- }
19
-
20
- .form-control .select2-container.select2-dropdown-open .select2-choices {
21
- border-radius: 3px 3px 0 0;
22
- }
23
-
24
- .form-control.select2-container .select2-choices {
25
- border: 0 !important;
26
- border-radius: 3px;
27
- }
28
-
29
- .control-group.warning .select2-container .select2-choice,
30
- .control-group.warning .select2-container .select2-choices,
31
- .control-group.warning .select2-container-active .select2-choice,
32
- .control-group.warning .select2-container-active .select2-choices,
33
- .control-group.warning .select2-dropdown-open.select2-drop-above .select2-choice,
34
- .control-group.warning .select2-dropdown-open.select2-drop-above .select2-choices,
35
- .control-group.warning .select2-container-multi.select2-container-active .select2-choices {
36
- border: 1px solid #C09853 !important;
37
- }
38
-
39
- .control-group.warning .select2-container .select2-choice div {
40
- border-left: 1px solid #C09853 !important;
41
- background: #FCF8E3 !important;
42
- }
43
-
44
- .control-group.error .select2-container .select2-choice,
45
- .control-group.error .select2-container .select2-choices,
46
- .control-group.error .select2-container-active .select2-choice,
47
- .control-group.error .select2-container-active .select2-choices,
48
- .control-group.error .select2-dropdown-open.select2-drop-above .select2-choice,
49
- .control-group.error .select2-dropdown-open.select2-drop-above .select2-choices,
50
- .control-group.error .select2-container-multi.select2-container-active .select2-choices {
51
- border: 1px solid #B94A48 !important;
52
- }
53
-
54
- .control-group.error .select2-container .select2-choice div {
55
- border-left: 1px solid #B94A48 !important;
56
- background: #F2DEDE !important;
57
- }
58
-
59
- .control-group.info .select2-container .select2-choice,
60
- .control-group.info .select2-container .select2-choices,
61
- .control-group.info .select2-container-active .select2-choice,
62
- .control-group.info .select2-container-active .select2-choices,
63
- .control-group.info .select2-dropdown-open.select2-drop-above .select2-choice,
64
- .control-group.info .select2-dropdown-open.select2-drop-above .select2-choices,
65
- .control-group.info .select2-container-multi.select2-container-active .select2-choices {
66
- border: 1px solid #3A87AD !important;
67
- }
68
-
69
- .control-group.info .select2-container .select2-choice div {
70
- border-left: 1px solid #3A87AD !important;
71
- background: #D9EDF7 !important;
72
- }
73
-
74
- .control-group.success .select2-container .select2-choice,
75
- .control-group.success .select2-container .select2-choices,
76
- .control-group.success .select2-container-active .select2-choice,
77
- .control-group.success .select2-container-active .select2-choices,
78
- .control-group.success .select2-dropdown-open.select2-drop-above .select2-choice,
79
- .control-group.success .select2-dropdown-open.select2-drop-above .select2-choices,
80
- .control-group.success .select2-container-multi.select2-container-active .select2-choices {
81
- border: 1px solid #468847 !important;
82
- }
83
-
84
- .control-group.success .select2-container .select2-choice div {
85
- border-left: 1px solid #468847 !important;
86
- background: #DFF0D8 !important;
87
- }
1
+ .form-control .select2-choice {
2
+ border: 0;
3
+ border-radius: 2px;
4
+ }
5
+
6
+ .form-control .select2-choice .select2-arrow {
7
+ border-radius: 0 2px 2px 0;
8
+ }
9
+
10
+ .form-control.select2-container {
11
+ height: auto !important;
12
+ padding: 0;
13
+ }
14
+
15
+ .form-control.select2-container.select2-dropdown-open {
16
+ border-color: #5897FB;
17
+ border-radius: 3px 3px 0 0;
18
+ }
19
+
20
+ .form-control .select2-container.select2-dropdown-open .select2-choices {
21
+ border-radius: 3px 3px 0 0;
22
+ }
23
+
24
+ .form-control.select2-container .select2-choices {
25
+ border: 0 !important;
26
+ border-radius: 3px;
27
+ }
28
+
29
+ .control-group.warning .select2-container .select2-choice,
30
+ .control-group.warning .select2-container .select2-choices,
31
+ .control-group.warning .select2-container-active .select2-choice,
32
+ .control-group.warning .select2-container-active .select2-choices,
33
+ .control-group.warning .select2-dropdown-open.select2-drop-above .select2-choice,
34
+ .control-group.warning .select2-dropdown-open.select2-drop-above .select2-choices,
35
+ .control-group.warning .select2-container-multi.select2-container-active .select2-choices {
36
+ border: 1px solid #C09853 !important;
37
+ }
38
+
39
+ .control-group.warning .select2-container .select2-choice div {
40
+ border-left: 1px solid #C09853 !important;
41
+ background: #FCF8E3 !important;
42
+ }
43
+
44
+ .control-group.error .select2-container .select2-choice,
45
+ .control-group.error .select2-container .select2-choices,
46
+ .control-group.error .select2-container-active .select2-choice,
47
+ .control-group.error .select2-container-active .select2-choices,
48
+ .control-group.error .select2-dropdown-open.select2-drop-above .select2-choice,
49
+ .control-group.error .select2-dropdown-open.select2-drop-above .select2-choices,
50
+ .control-group.error .select2-container-multi.select2-container-active .select2-choices {
51
+ border: 1px solid #B94A48 !important;
52
+ }
53
+
54
+ .control-group.error .select2-container .select2-choice div {
55
+ border-left: 1px solid #B94A48 !important;
56
+ background: #F2DEDE !important;
57
+ }
58
+
59
+ .control-group.info .select2-container .select2-choice,
60
+ .control-group.info .select2-container .select2-choices,
61
+ .control-group.info .select2-container-active .select2-choice,
62
+ .control-group.info .select2-container-active .select2-choices,
63
+ .control-group.info .select2-dropdown-open.select2-drop-above .select2-choice,
64
+ .control-group.info .select2-dropdown-open.select2-drop-above .select2-choices,
65
+ .control-group.info .select2-container-multi.select2-container-active .select2-choices {
66
+ border: 1px solid #3A87AD !important;
67
+ }
68
+
69
+ .control-group.info .select2-container .select2-choice div {
70
+ border-left: 1px solid #3A87AD !important;
71
+ background: #D9EDF7 !important;
72
+ }
73
+
74
+ .control-group.success .select2-container .select2-choice,
75
+ .control-group.success .select2-container .select2-choices,
76
+ .control-group.success .select2-container-active .select2-choice,
77
+ .control-group.success .select2-container-active .select2-choices,
78
+ .control-group.success .select2-dropdown-open.select2-drop-above .select2-choice,
79
+ .control-group.success .select2-dropdown-open.select2-drop-above .select2-choices,
80
+ .control-group.success .select2-container-multi.select2-container-active .select2-choices {
81
+ border: 1px solid #468847 !important;
82
+ }
83
+
84
+ .control-group.success .select2-container .select2-choice div {
85
+ border-left: 1px solid #468847 !important;
86
+ background: #DFF0D8 !important;
87
+ }
assets/deps/select2-3.5.2/select2.css CHANGED
@@ -1,704 +1,704 @@
1
- /*
2
- Version: 3.5.2 Timestamp: Sat Nov 1 14:43:36 EDT 2014
3
- */
4
- .select2-container {
5
- margin: 0;
6
- position: relative;
7
- display: inline-block;
8
- /* inline-block for ie7 */
9
- zoom: 1;
10
- *display: inline;
11
- vertical-align: middle;
12
- }
13
-
14
- .select2-container,
15
- .select2-drop,
16
- .select2-search,
17
- .select2-search input {
18
- /*
19
- Force border-box so that % widths fit the parent
20
- container without overlap because of margin/padding.
21
- More Info : http://www.quirksmode.org/css/box.html
22
- */
23
- -webkit-box-sizing: border-box; /* webkit */
24
- -moz-box-sizing: border-box; /* firefox */
25
- box-sizing: border-box; /* css3 */
26
- }
27
-
28
- .select2-container .select2-choice {
29
- display: block;
30
- height: 26px;
31
- padding: 0 0 0 8px;
32
- overflow: hidden;
33
- position: relative;
34
-
35
- border: 1px solid #aaa;
36
- white-space: nowrap;
37
- line-height: 26px;
38
- color: #444;
39
- text-decoration: none;
40
-
41
- border-radius: 4px;
42
-
43
- background-clip: padding-box;
44
-
45
- -webkit-touch-callout: none;
46
- -webkit-user-select: none;
47
- -moz-user-select: none;
48
- -ms-user-select: none;
49
- user-select: none;
50
-
51
- background-color: #fff;
52
- background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.5, #fff));
53
- background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 50%);
54
- background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 50%);
55
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0);
56
- background-image: linear-gradient(to top, #eee 0%, #fff 50%);
57
- }
58
-
59
- html[dir="rtl"] .select2-container .select2-choice {
60
- padding: 0 8px 0 0;
61
- }
62
-
63
- .select2-container.select2-drop-above .select2-choice {
64
- border-bottom-color: #aaa;
65
-
66
- border-radius: 0 0 4px 4px;
67
-
68
- background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.9, #fff));
69
- background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 90%);
70
- background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 90%);
71
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
72
- background-image: linear-gradient(to bottom, #eee 0%, #fff 90%);
73
- }
74
-
75
- .select2-container.select2-allowclear .select2-choice .select2-chosen {
76
- margin-right: 42px;
77
- }
78
-
79
- .select2-container .select2-choice > .select2-chosen {
80
- margin-right: 26px;
81
- display: block;
82
- overflow: hidden;
83
-
84
- white-space: nowrap;
85
-
86
- text-overflow: ellipsis;
87
- float: none;
88
- width: auto;
89
- }
90
-
91
- html[dir="rtl"] .select2-container .select2-choice > .select2-chosen {
92
- margin-left: 26px;
93
- margin-right: 0;
94
- }
95
-
96
- .select2-container .select2-choice abbr {
97
- display: none;
98
- width: 12px;
99
- height: 12px;
100
- position: absolute;
101
- right: 24px;
102
- top: 8px;
103
-
104
- font-size: 1px;
105
- text-decoration: none;
106
-
107
- border: 0;
108
- background: url('select2.png') right top no-repeat;
109
- cursor: pointer;
110
- outline: 0;
111
- }
112
-
113
- .select2-container.select2-allowclear .select2-choice abbr {
114
- display: inline-block;
115
- }
116
-
117
- .select2-container .select2-choice abbr:hover {
118
- background-position: right -11px;
119
- cursor: pointer;
120
- }
121
-
122
- .select2-drop-mask {
123
- border: 0;
124
- margin: 0;
125
- padding: 0;
126
- position: fixed;
127
- left: 0;
128
- top: 0;
129
- min-height: 100%;
130
- min-width: 100%;
131
- height: auto;
132
- width: auto;
133
- opacity: 0;
134
- z-index: 9998;
135
- /* styles required for IE to work */
136
- background-color: #fff;
137
- filter: alpha(opacity=0);
138
- }
139
-
140
- .select2-drop {
141
- width: 100%;
142
- margin-top: -1px;
143
- position: absolute;
144
- z-index: 9999;
145
- top: 100%;
146
-
147
- background: #fff;
148
- color: #000;
149
- border: 1px solid #aaa;
150
- border-top: 0;
151
-
152
- border-radius: 0 0 4px 4px;
153
-
154
- -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
155
- box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
156
- }
157
-
158
- .select2-drop.select2-drop-above {
159
- margin-top: 1px;
160
- border-top: 1px solid #aaa;
161
- border-bottom: 0;
162
-
163
- border-radius: 4px 4px 0 0;
164
-
165
- -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
166
- box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
167
- }
168
-
169
- .select2-drop-active {
170
- border: 1px solid #5897fb;
171
- border-top: none;
172
- }
173
-
174
- .select2-drop.select2-drop-above.select2-drop-active {
175
- border-top: 1px solid #5897fb;
176
- }
177
-
178
- .select2-drop-auto-width {
179
- border-top: 1px solid #aaa;
180
- width: auto;
181
- }
182
-
183
- .select2-drop-auto-width .select2-search {
184
- padding-top: 4px;
185
- }
186
-
187
- .select2-container .select2-choice .select2-arrow {
188
- display: inline-block;
189
- width: 18px;
190
- height: 100%;
191
- position: absolute;
192
- right: 0;
193
- top: 0;
194
-
195
- border-left: 1px solid #aaa;
196
- border-radius: 0 4px 4px 0;
197
-
198
- background-clip: padding-box;
199
-
200
- background: #ccc;
201
- background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee));
202
- background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%);
203
- background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%);
204
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0);
205
- background-image: linear-gradient(to top, #ccc 0%, #eee 60%);
206
- }
207
-
208
- html[dir="rtl"] .select2-container .select2-choice .select2-arrow {
209
- left: 0;
210
- right: auto;
211
-
212
- border-left: none;
213
- border-right: 1px solid #aaa;
214
- border-radius: 4px 0 0 4px;
215
- }
216
-
217
- .select2-container .select2-choice .select2-arrow b {
218
- display: block;
219
- width: 100%;
220
- height: 100%;
221
- background: url('select2.png') no-repeat 0 1px;
222
- }
223
-
224
- html[dir="rtl"] .select2-container .select2-choice .select2-arrow b {
225
- background-position: 2px 1px;
226
- }
227
-
228
- .select2-search {
229
- display: inline-block;
230
- width: 100%;
231
- min-height: 26px;
232
- margin: 0;
233
- padding-left: 4px;
234
- padding-right: 4px;
235
-
236
- position: relative;
237
- z-index: 10000;
238
-
239
- white-space: nowrap;
240
- }
241
-
242
- .select2-search input {
243
- width: 100%;
244
- height: auto !important;
245
- min-height: 26px;
246
- padding: 4px 20px 4px 5px;
247
- margin: 0;
248
-
249
- outline: 0;
250
- font-family: sans-serif;
251
- font-size: 1em;
252
-
253
- border: 1px solid #aaa;
254
- border-radius: 0;
255
-
256
- -webkit-box-shadow: none;
257
- box-shadow: none;
258
-
259
- background: #fff url('select2.png') no-repeat 100% -22px;
260
- background: url('select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
261
- background: url('select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
262
- background: url('select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
263
- background: url('select2.png') no-repeat 100% -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
264
- }
265
-
266
- html[dir="rtl"] .select2-search input {
267
- padding: 4px 5px 4px 20px;
268
-
269
- background: #fff url('select2.png') no-repeat -37px -22px;
270
- background: url('select2.png') no-repeat -37px -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
271
- background: url('select2.png') no-repeat -37px -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
272
- background: url('select2.png') no-repeat -37px -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
273
- background: url('select2.png') no-repeat -37px -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
274
- }
275
-
276
- .select2-drop.select2-drop-above .select2-search input {
277
- margin-top: 4px;
278
- }
279
-
280
- .select2-search input.select2-active {
281
- background: #fff url('select2-spinner.gif') no-repeat 100%;
282
- background: url('select2-spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
283
- background: url('select2-spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
284
- background: url('select2-spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
285
- background: url('select2-spinner.gif') no-repeat 100%, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
286
- }
287
-
288
- .select2-container-active .select2-choice,
289
- .select2-container-active .select2-choices {
290
- border: 1px solid #5897fb;
291
- outline: none;
292
-
293
- -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
294
- box-shadow: 0 0 5px rgba(0, 0, 0, .3);
295
- }
296
-
297
- .select2-dropdown-open .select2-choice {
298
- border-bottom-color: transparent;
299
- -webkit-box-shadow: 0 1px 0 #fff inset;
300
- box-shadow: 0 1px 0 #fff inset;
301
-
302
- border-bottom-left-radius: 0;
303
- border-bottom-right-radius: 0;
304
-
305
- background-color: #eee;
306
- background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(0.5, #eee));
307
- background-image: -webkit-linear-gradient(center bottom, #fff 0%, #eee 50%);
308
- background-image: -moz-linear-gradient(center bottom, #fff 0%, #eee 50%);
309
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);
310
- background-image: linear-gradient(to top, #fff 0%, #eee 50%);
311
- }
312
-
313
- .select2-dropdown-open.select2-drop-above .select2-choice,
314
- .select2-dropdown-open.select2-drop-above .select2-choices {
315
- border: 1px solid #5897fb;
316
- border-top-color: transparent;
317
-
318
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(0.5, #eee));
319
- background-image: -webkit-linear-gradient(center top, #fff 0%, #eee 50%);
320
- background-image: -moz-linear-gradient(center top, #fff 0%, #eee 50%);
321
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);
322
- background-image: linear-gradient(to bottom, #fff 0%, #eee 50%);
323
- }
324
-
325
- .select2-dropdown-open .select2-choice .select2-arrow {
326
- background: transparent;
327
- border-left: none;
328
- filter: none;
329
- }
330
- html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow {
331
- border-right: none;
332
- }
333
-
334
- .select2-dropdown-open .select2-choice .select2-arrow b {
335
- background-position: -18px 1px;
336
- }
337
-
338
- html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow b {
339
- background-position: -16px 1px;
340
- }
341
-
342
- .select2-hidden-accessible {
343
- border: 0;
344
- clip: rect(0 0 0 0);
345
- height: 1px;
346
- margin: -1px;
347
- overflow: hidden;
348
- padding: 0;
349
- position: absolute;
350
- width: 1px;
351
- }
352
-
353
- /* results */
354
- .select2-results {
355
- max-height: 200px;
356
- padding: 0 0 0 4px;
357
- margin: 4px 4px 4px 0;
358
- position: relative;
359
- overflow-x: hidden;
360
- overflow-y: auto;
361
- -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
362
- }
363
-
364
- html[dir="rtl"] .select2-results {
365
- padding: 0 4px 0 0;
366
- margin: 4px 0 4px 4px;
367
- }
368
-
369
- .select2-results ul.select2-result-sub {
370
- margin: 0;
371
- padding-left: 0;
372
- }
373
-
374
- .select2-results li {
375
- list-style: none;
376
- display: list-item;
377
- background-image: none;
378
- }
379
-
380
- .select2-results li.select2-result-with-children > .select2-result-label {
381
- font-weight: bold;
382
- }
383
-
384
- .select2-results .select2-result-label {
385
- padding: 3px 7px 4px;
386
- margin: 0;
387
- cursor: pointer;
388
-
389
- min-height: 1em;
390
-
391
- -webkit-touch-callout: none;
392
- -webkit-user-select: none;
393
- -moz-user-select: none;
394
- -ms-user-select: none;
395
- user-select: none;
396
- }
397
-
398
- .select2-results-dept-1 .select2-result-label { padding-left: 20px }
399
- .select2-results-dept-2 .select2-result-label { padding-left: 40px }
400
- .select2-results-dept-3 .select2-result-label { padding-left: 60px }
401
- .select2-results-dept-4 .select2-result-label { padding-left: 80px }
402
- .select2-results-dept-5 .select2-result-label { padding-left: 100px }
403
- .select2-results-dept-6 .select2-result-label { padding-left: 110px }
404
- .select2-results-dept-7 .select2-result-label { padding-left: 120px }
405
-
406
- .select2-results .select2-highlighted {
407
- background: #3875d7;
408
- color: #fff;
409
- }
410
-
411
- .select2-results li em {
412
- background: #feffde;
413
- font-style: normal;
414
- }
415
-
416
- .select2-results .select2-highlighted em {
417
- background: transparent;
418
- }
419
-
420
- .select2-results .select2-highlighted ul {
421
- background: #fff;
422
- color: #000;
423
- }
424
-
425
- .select2-results .select2-no-results,
426
- .select2-results .select2-searching,
427
- .select2-results .select2-ajax-error,
428
- .select2-results .select2-selection-limit {
429
- background: #f4f4f4;
430
- display: list-item;
431
- padding-left: 5px;
432
- }
433
-
434
- /*
435
- disabled look for disabled choices in the results dropdown
436
- */
437
- .select2-results .select2-disabled.select2-highlighted {
438
- color: #666;
439
- background: #f4f4f4;
440
- display: list-item;
441
- cursor: default;
442
- }
443
- .select2-results .select2-disabled {
444
- background: #f4f4f4;
445
- display: list-item;
446
- cursor: default;
447
- }
448
-
449
- .select2-results .select2-selected {
450
- display: none;
451
- }
452
-
453
- .select2-more-results.select2-active {
454
- background: #f4f4f4 url('select2-spinner.gif') no-repeat 100%;
455
- }
456
-
457
- .select2-results .select2-ajax-error {
458
- background: rgba(255, 50, 50, .2);
459
- }
460
-
461
- .select2-more-results {
462
- background: #f4f4f4;
463
- display: list-item;
464
- }
465
-
466
- /* disabled styles */
467
-
468
- .select2-container.select2-container-disabled .select2-choice {
469
- background-color: #f4f4f4;
470
- background-image: none;
471
- border: 1px solid #ddd;
472
- cursor: default;
473
- }
474
-
475
- .select2-container.select2-container-disabled .select2-choice .select2-arrow {
476
- background-color: #f4f4f4;
477
- background-image: none;
478
- border-left: 0;
479
- }
480
-
481
- .select2-container.select2-container-disabled .select2-choice abbr {
482
- display: none;
483
- }
484
-
485
-
486
- /* multiselect */
487
-
488
- .select2-container-multi .select2-choices {
489
- height: auto !important;
490
- height: 1%;
491
- margin: 0;
492
- padding: 0 5px 0 0;
493
- position: relative;
494
-
495
- border: 1px solid #aaa;
496
- cursor: text;
497
- overflow: hidden;
498
-
499
- background-color: #fff;
500
- background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eee), color-stop(15%, #fff));
501
- background-image: -webkit-linear-gradient(top, #eee 1%, #fff 15%);
502
- background-image: -moz-linear-gradient(top, #eee 1%, #fff 15%);
503
- background-image: linear-gradient(to bottom, #eee 1%, #fff 15%);
504
- }
505
-
506
- html[dir="rtl"] .select2-container-multi .select2-choices {
507
- padding: 0 0 0 5px;
508
- }
509
-
510
- .select2-locked {
511
- padding: 3px 5px 3px 5px !important;
512
- }
513
-
514
- .select2-container-multi .select2-choices {
515
- min-height: 26px;
516
- }
517
-
518
- .select2-container-multi.select2-container-active .select2-choices {
519
- border: 1px solid #5897fb;
520
- outline: none;
521
-
522
- -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
523
- box-shadow: 0 0 5px rgba(0, 0, 0, .3);
524
- }
525
- .select2-container-multi .select2-choices li {
526
- float: left;
527
- list-style: none;
528
- }
529
- html[dir="rtl"] .select2-container-multi .select2-choices li
530
- {
531
- float: right;
532
- }
533
- .select2-container-multi .select2-choices .select2-search-field {
534
- margin: 0;
535
- padding: 0;
536
- white-space: nowrap;
537
- }
538
-
539
- .select2-container-multi .select2-choices .select2-search-field input {
540
- padding: 5px;
541
- margin: 1px 0;
542
-
543
- font-family: sans-serif;
544
- font-size: 100%;
545
- color: #666;
546
- outline: 0;
547
- border: 0;
548
- -webkit-box-shadow: none;
549
- box-shadow: none;
550
- background: transparent !important;
551
- }
552
-
553
- .select2-container-multi .select2-choices .select2-search-field input.select2-active {
554
- background: #fff url('select2-spinner.gif') no-repeat 100% !important;
555
- }
556
-
557
- .select2-default {
558
- color: #999 !important;
559
- }
560
-
561
- .select2-container-multi .select2-choices .select2-search-choice {
562
- padding: 3px 5px 3px 18px;
563
- margin: 3px 0 3px 5px;
564
- position: relative;
565
-
566
- line-height: 13px;
567
- color: #333;
568
- cursor: default;
569
- border: 1px solid #aaaaaa;
570
-
571
- border-radius: 3px;
572
-
573
- -webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
574
- box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
575
-
576
- background-clip: padding-box;
577
-
578
- -webkit-touch-callout: none;
579
- -webkit-user-select: none;
580
- -moz-user-select: none;
581
- -ms-user-select: none;
582
- user-select: none;
583
-
584
- background-color: #e4e4e4;
585
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#f4f4f4', GradientType=0);
586
- background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eee));
587
- background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
588
- background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
589
- background-image: linear-gradient(to bottom, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
590
- }
591
- html[dir="rtl"] .select2-container-multi .select2-choices .select2-search-choice
592
- {
593
- margin: 3px 5px 3px 0;
594
- padding: 3px 18px 3px 5px;
595
- }
596
- .select2-container-multi .select2-choices .select2-search-choice .select2-chosen {
597
- cursor: default;
598
- }
599
- .select2-container-multi .select2-choices .select2-search-choice-focus {
600
- background: #d4d4d4;
601
- }
602
-
603
- .select2-search-choice-close {
604
- display: block;
605
- width: 12px;
606
- height: 13px;
607
- position: absolute;
608
- right: 3px;
609
- top: 4px;
610
-
611
- font-size: 1px;
612
- outline: none;
613
- background: url('select2.png') right top no-repeat;
614
- }
615
- html[dir="rtl"] .select2-search-choice-close {
616
- right: auto;
617
- left: 3px;
618
- }
619
-
620
- .select2-container-multi .select2-search-choice-close {
621
- left: 3px;
622
- }
623
-
624
- html[dir="rtl"] .select2-container-multi .select2-search-choice-close {
625
- left: auto;
626
- right: 2px;
627
- }
628
-
629
- .select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover {
630
- background-position: right -11px;
631
- }
632
- .select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close {
633
- background-position: right -11px;
634
- }
635
-
636
- /* disabled styles */
637
- .select2-container-multi.select2-container-disabled .select2-choices {
638
- background-color: #f4f4f4;
639
- background-image: none;
640
- border: 1px solid #ddd;
641
- cursor: default;
642
- }
643
-
644
- .select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice {
645
- padding: 3px 5px 3px 5px;
646
- border: 1px solid #ddd;
647
- background-image: none;
648
- background-color: #f4f4f4;
649
- }
650
-
651
- .select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none;
652
- background: none;
653
- }
654
- /* end multiselect */
655
-
656
-
657
- .select2-result-selectable .select2-match,
658
- .select2-result-unselectable .select2-match {
659
- text-decoration: underline;
660
- }
661
-
662
- .select2-offscreen, .select2-offscreen:focus {
663
- clip: rect(0 0 0 0) !important;
664
- width: 1px !important;
665
- height: 1px !important;
666
- border: 0 !important;
667
- margin: 0 !important;
668
- padding: 0 !important;
669
- overflow: hidden !important;
670
- position: absolute !important;
671
- outline: 0 !important;
672
- left: 0px !important;
673
- top: 0px !important;
674
- }
675
-
676
- .select2-display-none {
677
- display: none;
678
- }
679
-
680
- .select2-measure-scrollbar {
681
- position: absolute;
682
- top: -10000px;
683
- left: -10000px;
684
- width: 100px;
685
- height: 100px;
686
- overflow: scroll;
687
- }
688
-
689
- /* Retina-ize icons */
690
-
691
- @media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 2dppx) {
692
- .select2-search input,
693
- .select2-search-choice-close,
694
- .select2-container .select2-choice abbr,
695
- .select2-container .select2-choice .select2-arrow b {
696
- background-image: url('select2x2.png') !important;
697
- background-repeat: no-repeat !important;
698
- background-size: 60px 40px !important;
699
- }
700
-
701
- .select2-search input {
702
- background-position: 100% -21px !important;
703
- }
704
- }
1
+ /*
2
+ Version: 3.5.2 Timestamp: Sat Nov 1 14:43:36 EDT 2014
3
+ */
4
+ .select2-container {
5
+ margin: 0;
6
+ position: relative;
7
+ display: inline-block;
8
+ /* inline-block for ie7 */
9
+ zoom: 1;
10
+ *display: inline;
11
+ vertical-align: middle;
12
+ }
13
+
14
+ .select2-container,
15
+ .select2-drop,
16
+ .select2-search,
17
+ .select2-search input {
18
+ /*
19
+ Force border-box so that % widths fit the parent
20
+ container without overlap because of margin/padding.
21
+ More Info : http://www.quirksmode.org/css/box.html
22
+ */
23
+ -webkit-box-sizing: border-box; /* webkit */
24
+ -moz-box-sizing: border-box; /* firefox */
25
+ box-sizing: border-box; /* css3 */
26
+ }
27
+
28
+ .select2-container .select2-choice {
29
+ display: block;
30
+ height: 26px;
31
+ padding: 0 0 0 8px;
32
+ overflow: hidden;
33
+ position: relative;
34
+
35
+ border: 1px solid #aaa;
36
+ white-space: nowrap;
37
+ line-height: 26px;
38
+ color: #444;
39
+ text-decoration: none;
40
+
41
+ border-radius: 4px;
42
+
43
+ background-clip: padding-box;
44
+
45
+ -webkit-touch-callout: none;
46
+ -webkit-user-select: none;
47
+ -moz-user-select: none;
48
+ -ms-user-select: none;
49
+ user-select: none;
50
+
51
+ background-color: #fff;
52
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.5, #fff));
53
+ background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 50%);
54
+ background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 50%);
55
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0);
56
+ background-image: linear-gradient(to top, #eee 0%, #fff 50%);
57
+ }
58
+
59
+ html[dir="rtl"] .select2-container .select2-choice {
60
+ padding: 0 8px 0 0;
61
+ }
62
+
63
+ .select2-container.select2-drop-above .select2-choice {
64
+ border-bottom-color: #aaa;
65
+
66
+ border-radius: 0 0 4px 4px;
67
+
68
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.9, #fff));
69
+ background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 90%);
70
+ background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 90%);
71
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
72
+ background-image: linear-gradient(to bottom, #eee 0%, #fff 90%);
73
+ }
74
+
75
+ .select2-container.select2-allowclear .select2-choice .select2-chosen {
76
+ margin-right: 42px;
77
+ }
78
+
79
+ .select2-container .select2-choice > .select2-chosen {
80
+ margin-right: 26px;
81
+ display: block;
82
+ overflow: hidden;
83
+
84
+ white-space: nowrap;
85
+
86
+ text-overflow: ellipsis;
87
+ float: none;
88
+ width: auto;
89
+ }
90
+
91
+ html[dir="rtl"] .select2-container .select2-choice > .select2-chosen {
92
+ margin-left: 26px;
93
+ margin-right: 0;
94
+ }
95
+
96
+ .select2-container .select2-choice abbr {
97
+ display: none;
98
+ width: 12px;
99
+ height: 12px;
100
+ position: absolute;
101
+ right: 24px;
102
+ top: 8px;
103
+
104
+ font-size: 1px;
105
+ text-decoration: none;
106
+
107
+ border: 0;
108
+ background: url('select2.png') right top no-repeat;
109
+ cursor: pointer;
110
+ outline: 0;
111
+ }
112
+
113
+ .select2-container.select2-allowclear .select2-choice abbr {
114
+ display: inline-block;
115
+ }
116
+
117
+ .select2-container .select2-choice abbr:hover {
118
+ background-position: right -11px;
119
+ cursor: pointer;
120
+ }
121
+
122
+ .select2-drop-mask {
123
+ border: 0;
124
+ margin: 0;
125
+ padding: 0;
126
+ position: fixed;
127
+ left: 0;
128
+ top: 0;
129
+ min-height: 100%;
130
+ min-width: 100%;
131
+ height: auto;
132
+ width: auto;
133
+ opacity: 0;
134
+ z-index: 9998;
135
+ /* styles required for IE to work */
136
+ background-color: #fff;
137
+ filter: alpha(opacity=0);
138
+ }
139
+
140
+ .select2-drop {
141
+ width: 100%;
142
+ margin-top: -1px;
143
+ position: absolute;
144
+ z-index: 9999;
145
+ top: 100%;
146
+
147
+ background: #fff;
148
+ color: #000;
149
+ border: 1px solid #aaa;
150
+ border-top: 0;
151
+
152
+ border-radius: 0 0 4px 4px;
153
+
154
+ -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
155
+ box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
156
+ }
157
+
158
+ .select2-drop.select2-drop-above {
159
+ margin-top: 1px;
160
+ border-top: 1px solid #aaa;
161
+ border-bottom: 0;
162
+
163
+ border-radius: 4px 4px 0 0;
164
+
165
+ -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
166
+ box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
167
+ }
168
+
169
+ .select2-drop-active {
170
+ border: 1px solid #5897fb;
171
+ border-top: none;
172
+ }
173
+
174
+ .select2-drop.select2-drop-above.select2-drop-active {
175
+ border-top: 1px solid #5897fb;
176
+ }
177
+
178
+ .select2-drop-auto-width {
179
+ border-top: 1px solid #aaa;
180
+ width: auto;
181
+ }
182
+
183
+ .select2-drop-auto-width .select2-search {
184
+ padding-top: 4px;
185
+ }
186
+
187
+ .select2-container .select2-choice .select2-arrow {
188
+ display: inline-block;
189
+ width: 18px;
190
+ height: 100%;
191
+ position: absolute;
192
+ right: 0;
193
+ top: 0;
194
+
195
+ border-left: 1px solid #aaa;
196
+ border-radius: 0 4px 4px 0;
197
+
198
+ background-clip: padding-box;
199
+
200
+ background: #ccc;
201
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee));
202
+ background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%);
203
+ background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%);
204
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0);
205
+ background-image: linear-gradient(to top, #ccc 0%, #eee 60%);
206
+ }
207
+
208
+ html[dir="rtl"] .select2-container .select2-choice .select2-arrow {
209
+ left: 0;
210
+ right: auto;
211
+
212
+ border-left: none;
213
+ border-right: 1px solid #aaa;
214
+ border-radius: 4px 0 0 4px;
215
+ }
216
+
217
+ .select2-container .select2-choice .select2-arrow b {
218
+ display: block;
219
+ width: 100%;
220
+ height: 100%;
221
+ background: url('select2.png') no-repeat 0 1px;
222
+ }
223
+
224
+ html[dir="rtl"] .select2-container .select2-choice .select2-arrow b {
225
+ background-position: 2px 1px;
226
+ }
227
+
228
+ .select2-search {
229
+ display: inline-block;
230
+ width: 100%;
231
+ min-height: 26px;
232
+ margin: 0;
233
+ padding-left: 4px;
234
+ padding-right: 4px;
235
+
236
+ position: relative;
237
+ z-index: 10000;
238
+
239
+ white-space: nowrap;
240
+ }
241
+
242
+ .select2-search input {
243
+ width: 100%;
244
+ height: auto !important;
245
+ min-height: 26px;
246
+ padding: 4px 20px 4px 5px;
247
+ margin: 0;
248
+
249
+ outline: 0;
250
+ font-family: sans-serif;
251
+ font-size: 1em;
252
+
253
+ border: 1px solid #aaa;
254
+ border-radius: 0;
255
+
256
+ -webkit-box-shadow: none;
257
+ box-shadow: none;
258
+
259
+ background: #fff url('select2.png') no-repeat 100% -22px;
260
+ background: url('select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
261
+ background: url('select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
262
+ background: url('select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
263
+ background: url('select2.png') no-repeat 100% -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
264
+ }
265
+
266
+ html[dir="rtl"] .select2-search input {
267
+ padding: 4px 5px 4px 20px;
268
+
269
+ background: #fff url('select2.png') no-repeat -37px -22px;
270
+ background: url('select2.png') no-repeat -37px -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
271
+ background: url('select2.png') no-repeat -37px -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
272
+ background: url('select2.png') no-repeat -37px -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
273
+ background: url('select2.png') no-repeat -37px -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
274
+ }
275
+
276
+ .select2-drop.select2-drop-above .select2-search input {
277
+ margin-top: 4px;
278
+ }
279
+
280
+ .select2-search input.select2-active {
281
+ background: #fff url('select2-spinner.gif') no-repeat 100%;
282
+ background: url('select2-spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
283
+ background: url('select2-spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
284
+ background: url('select2-spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
285
+ background: url('select2-spinner.gif') no-repeat 100%, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
286
+ }
287
+
288
+ .select2-container-active .select2-choice,
289
+ .select2-container-active .select2-choices {
290
+ border: 1px solid #5897fb;
291
+ outline: none;
292
+
293
+ -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
294
+ box-shadow: 0 0 5px rgba(0, 0, 0, .3);
295
+ }
296
+
297
+ .select2-dropdown-open .select2-choice {
298
+ border-bottom-color: transparent;
299
+ -webkit-box-shadow: 0 1px 0 #fff inset;
300
+ box-shadow: 0 1px 0 #fff inset;
301
+
302
+ border-bottom-left-radius: 0;
303
+ border-bottom-right-radius: 0;
304
+
305
+ background-color: #eee;
306
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(0.5, #eee));
307
+ background-image: -webkit-linear-gradient(center bottom, #fff 0%, #eee 50%);
308
+ background-image: -moz-linear-gradient(center bottom, #fff 0%, #eee 50%);
309
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);
310
+ background-image: linear-gradient(to top, #fff 0%, #eee 50%);
311
+ }
312
+
313
+ .select2-dropdown-open.select2-drop-above .select2-choice,
314
+ .select2-dropdown-open.select2-drop-above .select2-choices {
315
+ border: 1px solid #5897fb;
316
+ border-top-color: transparent;
317
+
318
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(0.5, #eee));
319
+ background-image: -webkit-linear-gradient(center top, #fff 0%, #eee 50%);
320
+ background-image: -moz-linear-gradient(center top, #fff 0%, #eee 50%);
321
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);
322
+ background-image: linear-gradient(to bottom, #fff 0%, #eee 50%);
323
+ }
324
+
325
+ .select2-dropdown-open .select2-choice .select2-arrow {
326
+ background: transparent;
327
+ border-left: none;
328
+ filter: none;
329
+ }
330
+ html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow {
331
+ border-right: none;
332
+ }
333
+
334
+ .select2-dropdown-open .select2-choice .select2-arrow b {
335
+ background-position: -18px 1px;
336
+ }
337
+
338
+ html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow b {
339
+ background-position: -16px 1px;
340
+ }
341
+
342
+ .select2-hidden-accessible {
343
+ border: 0;
344
+ clip: rect(0 0 0 0);
345
+ height: 1px;
346
+ margin: -1px;
347
+ overflow: hidden;
348
+ padding: 0;
349
+ position: absolute;
350
+ width: 1px;
351
+ }
352
+
353
+ /* results */
354
+ .select2-results {
355
+ max-height: 200px;
356
+ padding: 0 0 0 4px;
357
+ margin: 4px 4px 4px 0;
358
+ position: relative;
359
+ overflow-x: hidden;
360
+ overflow-y: auto;
361
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
362
+ }
363
+
364
+ html[dir="rtl"] .select2-results {
365
+ padding: 0 4px 0 0;
366
+ margin: 4px 0 4px 4px;
367
+ }
368
+
369
+ .select2-results ul.select2-result-sub {
370
+ margin: 0;
371
+ padding-left: 0;
372
+ }
373
+
374
+ .select2-results li {
375
+ list-style: none;
376
+ display: list-item;
377
+ background-image: none;
378
+ }
379
+
380
+ .select2-results li.select2-result-with-children > .select2-result-label {
381
+ font-weight: bold;
382
+ }
383
+
384
+ .select2-results .select2-result-label {
385
+ padding: 3px 7px 4px;
386
+ margin: 0;
387
+ cursor: pointer;
388
+
389
+ min-height: 1em;
390
+
391
+ -webkit-touch-callout: none;
392
+ -webkit-user-select: none;
393
+ -moz-user-select: none;
394
+ -ms-user-select: none;
395
+ user-select: none;
396
+ }
397
+
398
+ .select2-results-dept-1 .select2-result-label { padding-left: 20px }
399
+ .select2-results-dept-2 .select2-result-label { padding-left: 40px }
400
+ .select2-results-dept-3 .select2-result-label { padding-left: 60px }
401
+ .select2-results-dept-4 .select2-result-label { padding-left: 80px }
402
+ .select2-results-dept-5 .select2-result-label { padding-left: 100px }
403
+ .select2-results-dept-6 .select2-result-label { padding-left: 110px }
404
+ .select2-results-dept-7 .select2-result-label { padding-left: 120px }
405
+
406
+ .select2-results .select2-highlighted {
407
+ background: #3875d7;
408
+ color: #fff;
409
+ }
410
+
411
+ .select2-results li em {
412
+ background: #feffde;
413
+ font-style: normal;
414
+ }
415
+
416
+ .select2-results .select2-highlighted em {
417
+ background: transparent;
418
+ }
419
+
420
+ .select2-results .select2-highlighted ul {
421
+ background: #fff;
422
+ color: #000;
423
+ }
424
+
425
+ .select2-results .select2-no-results,
426
+ .select2-results .select2-searching,
427
+ .select2-results .select2-ajax-error,
428
+ .select2-results .select2-selection-limit {
429
+ background: #f4f4f4;
430
+ display: list-item;
431
+ padding-left: 5px;
432
+ }
433
+
434
+ /*
435
+ disabled look for disabled choices in the results dropdown
436
+ */
437
+ .select2-results .select2-disabled.select2-highlighted {
438
+ color: #666;
439
+ background: #f4f4f4;
440
+ display: list-item;
441
+ cursor: default;
442
+ }
443
+ .select2-results .select2-disabled {
444
+ background: #f4f4f4;
445
+ display: list-item;
446
+ cursor: default;
447
+ }
448
+
449
+ .select2-results .select2-selected {
450
+ display: none;
451
+ }
452
+
453
+ .select2-more-results.select2-active {
454
+ background: #f4f4f4 url('select2-spinner.gif') no-repeat 100%;
455
+ }
456
+
457
+ .select2-results .select2-ajax-error {
458
+ background: rgba(255, 50, 50, .2);
459
+ }
460
+
461
+ .select2-more-results {
462
+ background: #f4f4f4;
463
+ display: list-item;
464
+ }
465
+
466
+ /* disabled styles */
467
+
468
+ .select2-container.select2-container-disabled .select2-choice {
469
+ background-color: #f4f4f4;
470
+ background-image: none;
471
+ border: 1px solid #ddd;
472
+ cursor: default;
473
+ }
474
+
475
+ .select2-container.select2-container-disabled .select2-choice .select2-arrow {
476
+ background-color: #f4f4f4;
477
+ background-image: none;
478
+ border-left: 0;
479
+ }
480
+
481
+ .select2-container.select2-container-disabled .select2-choice abbr {
482
+ display: none;
483
+ }
484
+
485
+
486
+ /* multiselect */
487
+
488
+ .select2-container-multi .select2-choices {
489
+ height: auto !important;
490
+ height: 1%;
491
+ margin: 0;
492
+ padding: 0 5px 0 0;
493
+ position: relative;
494
+
495
+ border: 1px solid #aaa;
496
+ cursor: text;
497
+ overflow: hidden;
498
+
499
+ background-color: #fff;
500
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eee), color-stop(15%, #fff));
501
+ background-image: -webkit-linear-gradient(top, #eee 1%, #fff 15%);
502
+ background-image: -moz-linear-gradient(top, #eee 1%, #fff 15%);
503
+ background-image: linear-gradient(to bottom, #eee 1%, #fff 15%);
504
+ }
505
+
506
+ html[dir="rtl"] .select2-container-multi .select2-choices {
507
+ padding: 0 0 0 5px;
508
+ }
509
+
510
+ .select2-locked {
511
+ padding: 3px 5px 3px 5px !important;
512
+ }
513
+
514
+ .select2-container-multi .select2-choices {
515
+ min-height: 26px;
516
+ }
517
+
518
+ .select2-container-multi.select2-container-active .select2-choices {
519
+ border: 1px solid #5897fb;
520
+ outline: none;
521
+
522
+ -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
523
+ box-shadow: 0 0 5px rgba(0, 0, 0, .3);
524
+ }
525
+ .select2-container-multi .select2-choices li {
526
+ float: left;
527
+ list-style: none;
528
+ }
529
+ html[dir="rtl"] .select2-container-multi .select2-choices li
530
+ {
531
+ float: right;
532
+ }
533
+ .select2-container-multi .select2-choices .select2-search-field {
534
+ margin: 0;
535
+ padding: 0;
536
+ white-space: nowrap;
537
+ }
538
+
539
+ .select2-container-multi .select2-choices .select2-search-field input {
540
+ padding: 5px;
541
+ margin: 1px 0;
542
+
543
+ font-family: sans-serif;
544
+ font-size: 100%;
545
+ color: #666;
546
+ outline: 0;
547
+ border: 0;
548
+ -webkit-box-shadow: none;
549
+ box-shadow: none;
550
+ background: transparent !important;
551
+ }
552
+
553
+ .select2-container-multi .select2-choices .select2-search-field input.select2-active {
554
+ background: #fff url('select2-spinner.gif') no-repeat 100% !important;
555
+ }
556
+
557
+ .select2-default {
558
+ color: #999 !important;
559
+ }
560
+
561
+ .select2-container-multi .select2-choices .select2-search-choice {
562
+ padding: 3px 5px 3px 18px;
563
+ margin: 3px 0 3px 5px;
564
+ position: relative;
565
+
566
+ line-height: 13px;
567
+ color: #333;
568
+ cursor: default;
569
+ border: 1px solid #aaaaaa;
570
+
571
+ border-radius: 3px;
572
+
573
+ -webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
574
+ box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
575
+
576
+ background-clip: padding-box;
577
+
578
+ -webkit-touch-callout: none;
579
+ -webkit-user-select: none;
580
+ -moz-user-select: none;
581
+ -ms-user-select: none;
582
+ user-select: none;
583
+
584
+ background-color: #e4e4e4;
585
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#f4f4f4', GradientType=0);
586
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eee));
587
+ background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
588
+ background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
589
+ background-image: linear-gradient(to bottom, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
590
+ }
591
+ html[dir="rtl"] .select2-container-multi .select2-choices .select2-search-choice
592
+ {
593
+ margin: 3px 5px 3px 0;
594
+ padding: 3px 18px 3px 5px;
595
+ }
596
+ .select2-container-multi .select2-choices .select2-search-choice .select2-chosen {
597
+ cursor: default;
598
+ }
599
+ .select2-container-multi .select2-choices .select2-search-choice-focus {
600
+ background: #d4d4d4;
601
+ }
602
+
603
+ .select2-search-choice-close {
604
+ display: block;
605
+ width: 12px;
606
+ height: 13px;
607
+ position: absolute;
608
+ right: 3px;
609
+ top: 4px;
610
+
611
+ font-size: 1px;
612
+ outline: none;
613
+ background: url('select2.png') right top no-repeat;
614
+ }
615
+ html[dir="rtl"] .select2-search-choice-close {
616
+ right: auto;
617
+ left: 3px;
618
+ }
619
+
620
+ .select2-container-multi .select2-search-choice-close {
621
+ left: 3px;
622
+ }
623
+
624
+ html[dir="rtl"] .select2-container-multi .select2-search-choice-close {
625
+ left: auto;
626
+ right: 2px;
627
+ }
628
+
629
+ .select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover {
630
+ background-position: right -11px;
631
+ }
632
+ .select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close {
633
+ background-position: right -11px;
634
+ }
635
+
636
+ /* disabled styles */
637
+ .select2-container-multi.select2-container-disabled .select2-choices {
638
+ background-color: #f4f4f4;
639
+ background-image: none;
640
+ border: 1px solid #ddd;
641
+ cursor: default;
642
+ }
643
+
644
+ .select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice {
645
+ padding: 3px 5px 3px 5px;
646
+ border: 1px solid #ddd;
647
+ background-image: none;
648
+ background-color: #f4f4f4;
649
+ }
650
+
651
+ .select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none;
652
+ background: none;
653
+ }
654
+ /* end multiselect */
655
+
656
+
657
+ .select2-result-selectable .select2-match,
658
+ .select2-result-unselectable .select2-match {
659
+ text-decoration: underline;
660
+ }
661
+
662
+ .select2-offscreen, .select2-offscreen:focus {
663
+ clip: rect(0 0 0 0) !important;
664
+ width: 1px !important;
665
+ height: 1px !important;
666
+ border: 0 !important;
667
+ margin: 0 !important;
668
+ padding: 0 !important;
669
+ overflow: hidden !important;
670
+ position: absolute !important;
671
+ outline: 0 !important;
672
+ left: 0px !important;
673
+ top: 0px !important;
674
+ }
675
+
676
+ .select2-display-none {
677
+ display: none;
678
+ }
679
+
680
+ .select2-measure-scrollbar {
681
+ position: absolute;
682
+ top: -10000px;
683
+ left: -10000px;
684
+ width: 100px;
685
+ height: 100px;
686
+ overflow: scroll;
687
+ }
688
+
689
+ /* Retina-ize icons */
690
+
691
+ @media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 2dppx) {
692
+ .select2-search input,
693
+ .select2-search-choice-close,
694
+ .select2-container .select2-choice abbr,
695
+ .select2-container .select2-choice .select2-arrow b {
696
+ background-image: url('select2x2.png') !important;
697
+ background-repeat: no-repeat !important;
698
+ background-size: 60px 40px !important;
699
+ }
700
+
701
+ .select2-search input {
702
+ background-position: 100% -21px !important;
703
+ }
704
+ }
assets/deps/select2-3.5.2/select2.jquery.json CHANGED
@@ -1,36 +1,36 @@
1
- {
2
- "name": "select2",
3
- "title": "Select2",
4
- "description": "Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.",
5
- "keywords": [
6
- "select",
7
- "autocomplete",
8
- "typeahead",
9
- "dropdown",
10
- "multiselect",
11
- "tag",
12
- "tagging"
13
- ],
14
- "version": "3.5.2",
15
- "author": {
16
- "name": "Igor Vaynberg",
17
- "url": "https://github.com/ivaynberg"
18
- },
19
- "licenses": [
20
- {
21
- "type": "Apache",
22
- "url": "http://www.apache.org/licenses/LICENSE-2.0"
23
- },
24
- {
25
- "type": "GPL v2",
26
- "url": "http://www.gnu.org/licenses/gpl-2.0.html"
27
- }
28
- ],
29
- "bugs": "https://github.com/ivaynberg/select2/issues",
30
- "homepage": "http://ivaynberg.github.com/select2",
31
- "docs": "http://ivaynberg.github.com/select2/",
32
- "download": "https://github.com/ivaynberg/select2/tags",
33
- "dependencies": {
34
- "jquery": ">=1.7.1"
35
- }
36
- }
1
+ {
2
+ "name": "select2",
3
+ "title": "Select2",
4
+ "description": "Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.",
5
+ "keywords": [
6
+ "select",
7
+ "autocomplete",
8
+ "typeahead",
9
+ "dropdown",
10
+ "multiselect",
11
+ "tag",
12
+ "tagging"
13
+ ],
14
+ "version": "3.5.2",
15
+ "author": {
16
+ "name": "Igor Vaynberg",
17
+ "url": "https://github.com/ivaynberg"
18
+ },
19
+ "licenses": [
20
+ {
21
+ "type": "Apache",
22
+ "url": "http://www.apache.org/licenses/LICENSE-2.0"
23
+ },
24
+ {
25
+ "type": "GPL v2",
26
+ "url": "http://www.gnu.org/licenses/gpl-2.0.html"
27
+ }
28
+ ],
29
+ "bugs": "https://github.com/ivaynberg/select2/issues",
30
+ "homepage": "http://ivaynberg.github.com/select2",
31
+ "docs": "http://ivaynberg.github.com/select2/",
32
+ "download": "https://github.com/ivaynberg/select2/tags",
33
+ "dependencies": {
34
+ "jquery": ">=1.7.1"
35
+ }
36
+ }
assets/deps/select2-3.5.2/select2.js CHANGED
@@ -1,3541 +1,3541 @@
1
- /*
2
- Copyright 2012 Igor Vaynberg
3
-
4
- Version: 3.5.2 Timestamp: Sat Nov 1 14:43:36 EDT 2014
5
-
6
- This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
7
- General Public License version 2 (the "GPL License"). You may choose either license to govern your
8
- use of this software only upon the condition that you accept all of the terms of either the Apache
9
- License or the GPL License.
10
-
11
- You may obtain a copy of the Apache License and the GPL License at:
12
-
13
- http://www.apache.org/licenses/LICENSE-2.0
14
- http://www.gnu.org/licenses/gpl-2.0.html
15
-
16
- Unless required by applicable law or agreed to in writing, software distributed under the
17
- Apache License or the GPL License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
18
- CONDITIONS OF ANY KIND, either express or implied. See the Apache License and the GPL License for
19
- the specific language governing permissions and limitations under the Apache License and the GPL License.
20
- */
21
- (function ($) {
22
- if(typeof $.fn.each2 == "undefined") {
23
- $.extend($.fn, {
24
- /*
25
- * 4-10 times faster .each replacement
26
- * use it carefully, as it overrides jQuery context of element on each iteration
27
- */
28
- each2 : function (c) {
29
- var j = $([0]), i = -1, l = this.length;
30
- while (
31
- ++i < l
32
- && (j.context = j[0] = this[i])
33
- && c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object
34
- );
35
- return this;
36
- }
37
- });
38
- }
39
- })(jQuery);
40
-
41
- (function ($, undefined) {
42
- "use strict";
43
- /*global document, window, jQuery, console */
44
-
45
- if (window.Select2 !== undefined) {
46
- return;
47
- }
48
-
49
- var AbstractSelect2, SingleSelect2, MultiSelect2, nextUid, sizer,
50
- lastMousePosition={x:0,y:0}, $document, scrollBarDimensions,
51
-
52
- KEY = {
53
- TAB: 9,
54
- ENTER: 13,
55
- ESC: 27,
56
- SPACE: 32,
57
- LEFT: 37,
58
- UP: 38,
59
- RIGHT: 39,
60
- DOWN: 40,
61
- SHIFT: 16,
62
- CTRL: 17,
63
- ALT: 18,
64
- PAGE_UP: 33,
65
- PAGE_DOWN: 34,
66
- HOME: 36,
67
- END: 35,
68
- BACKSPACE: 8,
69
- DELETE: 46,
70
- isArrow: function (k) {
71
- k = k.which ? k.which : k;
72
- switch (k) {
73
- case KEY.LEFT:
74
- case KEY.RIGHT:
75
- case KEY.UP:
76
- case KEY.DOWN:
77
- return true;
78
- }
79
- return false;
80
- },
81
- isControl: function (e) {
82
- var k = e.which;
83
- switch (k) {
84
- case KEY.SHIFT:
85
- case KEY.CTRL:
86
- case KEY.ALT:
87
- return true;
88
- }
89
-
90
- if (e.metaKey) return true;
91
-
92
- return false;
93
- },
94
- isFunctionKey: function (k) {
95
- k = k.which ? k.which : k;
96
- return k >= 112 && k <= 123;
97
- }
98
- },
99
- MEASURE_SCROLLBAR_TEMPLATE = "<div class='select2-measure-scrollbar'></div>",
100
-
101
- DIACRITICS = {"\u24B6":"A","\uFF21":"A","\u00C0":"A","\u00C1":"A","\u00C2":"A","\u1EA6":"A","\u1EA4":"A","\u1EAA":"A","\u1EA8":"A","\u00C3":"A","\u0100":"A","\u0102":"A","\u1EB0":"A","\u1EAE":"A","\u1EB4":"A","\u1EB2":"A","\u0226":"A","\u01E0":"A","\u00C4":"A","\u01DE":"A","\u1EA2":"A","\u00C5":"A","\u01FA":"A","\u01CD":"A","\u0200":"A","\u0202":"A","\u1EA0":"A","\u1EAC":"A","\u1EB6":"A","\u1E00":"A","\u0104":"A","\u023A":"A","\u2C6F":"A","\uA732":"AA","\u00C6":"AE","\u01FC":"AE","\u01E2":"AE","\uA734":"AO","\uA736":"AU","\uA738":"AV","\uA73A":"AV","\uA73C":"AY","\u24B7":"B","\uFF22":"B","\u1E02":"B","\u1E04":"B","\u1E06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24B8":"C","\uFF23":"C","\u0106":"C","\u0108":"C","\u010A":"C","\u010C":"C","\u00C7":"C","\u1E08":"C","\u0187":"C","\u023B":"C","\uA73E":"C","\u24B9":"D","\uFF24":"D","\u1E0A":"D","\u010E":"D","\u1E0C":"D","\u1E10":"D","\u1E12":"D","\u1E0E":"D","\u0110":"D","\u018B":"D","\u018A":"D","\u0189":"D","\uA779":"D","\u01F1":"DZ","\u01C4":"DZ","\u01F2":"Dz","\u01C5":"Dz","\u24BA":"E","\uFF25":"E","\u00C8":"E","\u00C9":"E","\u00CA":"E","\u1EC0":"E","\u1EBE":"E","\u1EC4":"E","\u1EC2":"E","\u1EBC":"E","\u0112":"E","\u1E14":"E","\u1E16":"E","\u0114":"E","\u0116":"E","\u00CB":"E","\u1EBA":"E","\u011A":"E","\u0204":"E","\u0206":"E","\u1EB8":"E","\u1EC6":"E","\u0228":"E","\u1E1C":"E","\u0118":"E","\u1E18":"E","\u1E1A":"E","\u0190":"E","\u018E":"E","\u24BB":"F","\uFF26":"F","\u1E1E":"F","\u0191":"F","\uA77B":"F","\u24BC":"G","\uFF27":"G","\u01F4":"G","\u011C":"G","\u1E20":"G","\u011E":"G","\u0120":"G","\u01E6":"G","\u0122":"G","\u01E4":"G","\u0193":"G","\uA7A0":"G","\uA77D":"G","\uA77E":"G","\u24BD":"H","\uFF28":"H","\u0124":"H","\u1E22":"H","\u1E26":"H","\u021E":"H","\u1E24":"H","\u1E28":"H","\u1E2A":"H","\u0126":"H","\u2C67":"H","\u2C75":"H","\uA78D":"H","\u24BE":"I","\uFF29":"I","\u00CC":"I","\u00CD":"I","\u00CE":"I","\u0128":"I","\u012A":"I","\u012C":"I","\u0130":"I","\u00CF":"I","\u1E2E":"I","\u1EC8":"I","\u01CF":"I","\u0208":"I","\u020A":"I","\u1ECA":"I","\u012E":"I","\u1E2C":"I","\u0197":"I","\u24BF":"J","\uFF2A":"J","\u0134":"J","\u0248":"J","\u24C0":"K","\uFF2B":"K","\u1E30":"K","\u01E8":"K","\u1E32":"K","\u0136":"K","\u1E34":"K","\u0198":"K","\u2C69":"K","\uA740":"K","\uA742":"K","\uA744":"K","\uA7A2":"K","\u24C1":"L","\uFF2C":"L","\u013F":"L","\u0139":"L","\u013D":"L","\u1E36":"L","\u1E38":"L","\u013B":"L","\u1E3C":"L","\u1E3A":"L","\u0141":"L","\u023D":"L","\u2C62":"L","\u2C60":"L","\uA748":"L","\uA746":"L","\uA780":"L","\u01C7":"LJ","\u01C8":"Lj","\u24C2":"M","\uFF2D":"M","\u1E3E":"M","\u1E40":"M","\u1E42":"M","\u2C6E":"M","\u019C":"M","\u24C3":"N","\uFF2E":"N","\u01F8":"N","\u0143":"N","\u00D1":"N","\u1E44":"N","\u0147":"N","\u1E46":"N","\u0145":"N","\u1E4A":"N","\u1E48":"N","\u0220":"N","\u019D":"N","\uA790":"N","\uA7A4":"N","\u01CA":"NJ","\u01CB":"Nj","\u24C4":"O","\uFF2F":"O","\u00D2":"O","\u00D3":"O","\u00D4":"O","\u1ED2":"O","\u1ED0":"O","\u1ED6":"O","\u1ED4":"O","\u00D5":"O","\u1E4C":"O","\u022C":"O","\u1E4E":"O","\u014C":"O","\u1E50":"O","\u1E52":"O","\u014E":"O","\u022E":"O","\u0230":"O","\u00D6":"O","\u022A":"O","\u1ECE":"O","\u0150":"O","\u01D1":"O","\u020C":"O","\u020E":"O","\u01A0":"O","\u1EDC":"O","\u1EDA":"O","\u1EE0":"O","\u1EDE":"O","\u1EE2":"O","\u1ECC":"O","\u1ED8":"O","\u01EA":"O","\u01EC":"O","\u00D8":"O","\u01FE":"O","\u0186":"O","\u019F":"O","\uA74A":"O","\uA74C":"O","\u01A2":"OI","\uA74E":"OO","\u0222":"OU","\u24C5":"P","\uFF30":"P","\u1E54":"P","\u1E56":"P","\u01A4":"P","\u2C63":"P","\uA750":"P","\uA752":"P","\uA754":"P","\u24C6":"Q","\uFF31":"Q","\uA756":"Q","\uA758":"Q","\u024A":"Q","\u24C7":"R","\uFF32":"R","\u0154":"R","\u1E58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1E5A":"R","\u1E5C":"R","\u0156":"R","\u1E5E":"R","\u024C":"R","\u2C64":"R","\uA75A":"R","\uA7A6":"R","\uA782":"R","\u24C8":"S","\uFF33":"S","\u1E9E":"S","\u015A":"S","\u1E64":"S","\u015C":"S","\u1E60":"S","\u0160":"S","\u1E66":"S","\u1E62":"S","\u1E68":"S","\u0218":"S","\u015E":"S","\u2C7E":"S","\uA7A8":"S","\uA784":"S","\u24C9":"T","\uFF34":"T","\u1E6A":"T","\u0164":"T","\u1E6C":"T","\u021A":"T","\u0162":"T","\u1E70":"T","\u1E6E":"T","\u0166":"T","\u01AC":"T","\u01AE":"T","\u023E":"T","\uA786":"T","\uA728":"TZ","\u24CA":"U","\uFF35":"U","\u00D9":"U","\u00DA":"U","\u00DB":"U","\u0168":"U","\u1E78":"U","\u016A":"U","\u1E7A":"U","\u016C":"U","\u00DC":"U","\u01DB":"U","\u01D7":"U","\u01D5":"U","\u01D9":"U","\u1EE6":"U","\u016E":"U","\u0170":"U","\u01D3":"U","\u0214":"U","\u0216":"U","\u01AF":"U","\u1EEA":"U","\u1EE8":"U","\u1EEE":"U","\u1EEC":"U","\u1EF0":"U","\u1EE4":"U","\u1E72":"U","\u0172":"U","\u1E76":"U","\u1E74":"U","\u0244":"U","\u24CB":"V","\uFF36":"V","\u1E7C":"V","\u1E7E":"V","\u01B2":"V","\uA75E":"V","\u0245":"V","\uA760":"VY","\u24CC":"W","\uFF37":"W","\u1E80":"W","\u1E82":"W","\u0174":"W","\u1E86":"W","\u1E84":"W","\u1E88":"W","\u2C72":"W","\u24CD":"X","\uFF38":"X","\u1E8A":"X","\u1E8C":"X","\u24CE":"Y","\uFF39":"Y","\u1EF2":"Y","\u00DD":"Y","\u0176":"Y","\u1EF8":"Y","\u0232":"Y","\u1E8E":"Y","\u0178":"Y","\u1EF6":"Y","\u1EF4":"Y","\u01B3":"Y","\u024E":"Y","\u1EFE":"Y","\u24CF":"Z","\uFF3A":"Z","\u0179":"Z","\u1E90":"Z","\u017B":"Z","\u017D":"Z","\u1E92":"Z","\u1E94":"Z","\u01B5":"Z","\u0224":"Z","\u2C7F":"Z","\u2C6B":"Z","\uA762":"Z","\u24D0":"a","\uFF41":"a","\u1E9A":"a","\u00E0":"a","\u00E1":"a","\u00E2":"a","\u1EA7":"a","\u1EA5":"a","\u1EAB":"a","\u1EA9":"a","\u00E3":"a","\u0101":"a","\u0103":"a","\u1EB1":"a","\u1EAF":"a","\u1EB5":"a","\u1EB3":"a","\u0227":"a","\u01E1":"a","\u00E4":"a","\u01DF":"a","\u1EA3":"a","\u00E5":"a","\u01FB":"a","\u01CE":"a","\u0201":"a","\u0203":"a","\u1EA1":"a","\u1EAD":"a","\u1EB7":"a","\u1E01":"a","\u0105":"a","\u2C65":"a","\u0250":"a","\uA733":"aa","\u00E6":"ae","\u01FD":"ae","\u01E3":"ae","\uA735":"ao","\uA737":"au","\uA739":"av","\uA73B":"av","\uA73D":"ay","\u24D1":"b","\uFF42":"b","\u1E03":"b","\u1E05":"b","\u1E07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24D2":"c","\uFF43":"c","\u0107":"c","\u0109":"c","\u010B":"c","\u010D":"c","\u00E7":"c","\u1E09":"c","\u0188":"c","\u023C":"c","\uA73F":"c","\u2184":"c","\u24D3":"d","\uFF44":"d","\u1E0B":"d","\u010F":"d","\u1E0D":"d","\u1E11":"d","\u1E13":"d","\u1E0F":"d","\u0111":"d","\u018C":"d","\u0256":"d","\u0257":"d","\uA77A":"d","\u01F3":"dz","\u01C6":"dz","\u24D4":"e","\uFF45":"e","\u00E8":"e","\u00E9":"e","\u00EA":"e","\u1EC1":"e","\u1EBF":"e","\u1EC5":"e","\u1EC3":"e","\u1EBD":"e","\u0113":"e","\u1E15":"e","\u1E17":"e","\u0115":"e","\u0117":"e","\u00EB":"e","\u1EBB":"e","\u011B":"e","\u0205":"e","\u0207":"e","\u1EB9":"e","\u1EC7":"e","\u0229":"e","\u1E1D":"e","\u0119":"e","\u1E19":"e","\u1E1B":"e","\u0247":"e","\u025B":"e","\u01DD":"e","\u24D5":"f","\uFF46":"f","\u1E1F":"f","\u0192":"f","\uA77C":"f","\u24D6":"g","\uFF47":"g","\u01F5":"g","\u011D":"g","\u1E21":"g","\u011F":"g","\u0121":"g","\u01E7":"g","\u0123":"g","\u01E5":"g","\u0260":"g","\uA7A1":"g","\u1D79":"g","\uA77F":"g","\u24D7":"h","\uFF48":"h","\u0125":"h","\u1E23":"h","\u1E27":"h","\u021F":"h","\u1E25":"h","\u1E29":"h","\u1E2B":"h","\u1E96":"h","\u0127":"h","\u2C68":"h","\u2C76":"h","\u0265":"h","\u0195":"hv","\u24D8":"i","\uFF49":"i","\u00EC":"i","\u00ED":"i","\u00EE":"i","\u0129":"i","\u012B":"i","\u012D":"i","\u00EF":"i","\u1E2F":"i","\u1EC9":"i","\u01D0":"i","\u0209":"i","\u020B":"i","\u1ECB":"i","\u012F":"i","\u1E2D":"i","\u0268":"i","\u0131":"i","\u24D9":"j","\uFF4A":"j","\u0135":"j","\u01F0":"j","\u0249":"j","\u24DA":"k","\uFF4B":"k","\u1E31":"k","\u01E9":"k","\u1E33":"k","\u0137":"k","\u1E35":"k","\u0199":"k","\u2C6A":"k","\uA741":"k","\uA743":"k","\uA745":"k","\uA7A3":"k","\u24DB":"l","\uFF4C":"l","\u0140":"l","\u013A":"l","\u013E":"l","\u1E37":"l","\u1E39":"l","\u013C":"l","\u1E3D":"l","\u1E3B":"l","\u017F":"l","\u0142":"l","\u019A":"l","\u026B":"l","\u2C61":"l","\uA749":"l","\uA781":"l","\uA747":"l","\u01C9":"lj","\u24DC":"m","\uFF4D":"m","\u1E3F":"m","\u1E41":"m","\u1E43":"m","\u0271":"m","\u026F":"m","\u24DD":"n","\uFF4E":"n","\u01F9":"n","\u0144":"n","\u00F1":"n","\u1E45":"n","\u0148":"n","\u1E47":"n","\u0146":"n","\u1E4B":"n","\u1E49":"n","\u019E":"n","\u0272":"n","\u0149":"n","\uA791":"n","\uA7A5":"n","\u01CC":"nj","\u24DE":"o","\uFF4F":"o","\u00F2":"o","\u00F3":"o","\u00F4":"o","\u1ED3":"o","\u1ED1":"o","\u1ED7":"o","\u1ED5":"o","\u00F5":"o","\u1E4D":"o","\u022D":"o","\u1E4F":"o","\u014D":"o","\u1E51":"o","\u1E53":"o","\u014F":"o","\u022F":"o","\u0231":"o","\u00F6":"o","\u022B":"o","\u1ECF":"o","\u0151":"o","\u01D2":"o","\u020D":"o","\u020F":"o","\u01A1":"o","\u1EDD":"o","\u1EDB":"o","\u1EE1":"o","\u1EDF":"o","\u1EE3":"o","\u1ECD":"o","\u1ED9":"o","\u01EB":"o","\u01ED":"o","\u00F8":"o","\u01FF":"o","\u0254":"o","\uA74B":"o","\uA74D":"o","\u0275":"o","\u01A3":"oi","\u0223":"ou","\uA74F":"oo","\u24DF":"p","\uFF50":"p","\u1E55":"p","\u1E57":"p","\u01A5":"p","\u1D7D":"p","\uA751":"p","\uA753":"p","\uA755":"p","\u24E0":"q","\uFF51":"q","\u024B":"q","\uA757":"q","\uA759":"q","\u24E1":"r","\uFF52":"r","\u0155":"r","\u1E59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1E5B":"r","\u1E5D":"r","\u0157":"r","\u1E5F":"r","\u024D":"r","\u027D":"r","\uA75B":"r","\uA7A7":"r","\uA783":"r","\u24E2":"s","\uFF53":"s","\u00DF":"s","\u015B":"s","\u1E65":"s","\u015D":"s","\u1E61":"s","\u0161":"s","\u1E67":"s","\u1E63":"s","\u1E69":"s","\u0219":"s","\u015F":"s","\u023F":"s","\uA7A9":"s","\uA785":"s","\u1E9B":"s","\u24E3":"t","\uFF54":"t","\u1E6B":"t","\u1E97":"t","\u0165":"t","\u1E6D":"t","\u021B":"t","\u0163":"t","\u1E71":"t","\u1E6F":"t","\u0167":"t","\u01AD":"t","\u0288":"t","\u2C66":"t","\uA787":"t","\uA729":"tz","\u24E4":"u","\uFF55":"u","\u00F9":"u","\u00FA":"u","\u00FB":"u","\u0169":"u","\u1E79":"u","\u016B":"u","\u1E7B":"u","\u016D":"u","\u00FC":"u","\u01DC":"u","\u01D8":"u","\u01D6":"u","\u01DA":"u","\u1EE7":"u","\u016F":"u","\u0171":"u","\u01D4":"u","\u0215":"u","\u0217":"u","\u01B0":"u","\u1EEB":"u","\u1EE9":"u","\u1EEF":"u","\u1EED":"u","\u1EF1":"u","\u1EE5":"u","\u1E73":"u","\u0173":"u","\u1E77":"u","\u1E75":"u","\u0289":"u","\u24E5":"v","\uFF56":"v","\u1E7D":"v","\u1E7F":"v","\u028B":"v","\uA75F":"v","\u028C":"v","\uA761":"vy","\u24E6":"w","\uFF57":"w","\u1E81":"w","\u1E83":"w","\u0175":"w","\u1E87":"w","\u1E85":"w","\u1E98":"w","\u1E89":"w","\u2C73":"w","\u24E7":"x","\uFF58":"x","\u1E8B":"x","\u1E8D":"x","\u24E8":"y","\uFF59":"y","\u1EF3":"y","\u00FD":"y","\u0177":"y","\u1EF9":"y","\u0233":"y","\u1E8F":"y","\u00FF":"y","\u1EF7":"y","\u1E99":"y","\u1EF5":"y","\u01B4":"y","\u024F":"y","\u1EFF":"y","\u24E9":"z","\uFF5A":"z","\u017A":"z","\u1E91":"z","\u017C":"z","\u017E":"z","\u1E93":"z","\u1E95":"z","\u01B6":"z","\u0225":"z","\u0240":"z","\u2C6C":"z","\uA763":"z","\u0386":"\u0391","\u0388":"\u0395","\u0389":"\u0397","\u038A":"\u0399","\u03AA":"\u0399","\u038C":"\u039F","\u038E":"\u03A5","\u03AB":"\u03A5","\u038F":"\u03A9","\u03AC":"\u03B1","\u03AD":"\u03B5","\u03AE":"\u03B7","\u03AF":"\u03B9","\u03CA":"\u03B9","\u0390":"\u03B9","\u03CC":"\u03BF","\u03CD":"\u03C5","\u03CB":"\u03C5","\u03B0":"\u03C5","\u03C9":"\u03C9","\u03C2":"\u03C3"};
102
-
103
- $document = $(document);
104
-
105
- nextUid=(function() { var counter=1; return function() { return counter++; }; }());
106
-
107
-
108
- function reinsertElement(element) {
109
- var placeholder = $(document.createTextNode(''));
110
-
111
- element.before(placeholder);
112
- placeholder.before(element);
113
- placeholder.remove();
114
- }
115
-
116
- function stripDiacritics(str) {
117
- // Used 'uni range + named function' from http://jsperf.com/diacritics/18
118
- function match(a) {
119
- return DIACRITICS[a] || a;
120
- }
121
-
122
- return str.replace(/[^\u0000-\u007E]/g, match);
123
- }
124
-
125
- function indexOf(value, array) {
126
- var i = 0, l = array.length;
127
- for (; i < l; i = i + 1) {
128
- if (equal(value, array[i])) return i;
129
- }
130
- return -1;
131
- }
132
-
133
- function measureScrollbar () {
134
- var $template = $( MEASURE_SCROLLBAR_TEMPLATE );
135
- $template.appendTo(document.body);
136
-
137
- var dim = {
138
- width: $template.width() - $template[0].clientWidth,
139
- height: $template.height() - $template[0].clientHeight
140
- };
141
- $template.remove();
142
-
143
- return dim;
144
- }
145
-
146
- /**
147
- * Compares equality of a and b
148
- * @param a
149
- * @param b
150
- */
151
- function equal(a, b) {
152
- if (a === b) return true;
153
- if (a === undefined || b === undefined) return false;
154
- if (a === null || b === null) return false;
155
- // Check whether 'a' or 'b' is a string (primitive or object).
156
- // The concatenation of an empty string (+'') converts its argument to a string's primitive.
157
- if (a.constructor === String) return a+'' === b+''; // a+'' - in case 'a' is a String object
158
- if (b.constructor === String) return b+'' === a+''; // b+'' - in case 'b' is a String object
159
- return false;
160
- }
161
-
162
- /**
163
- * Splits the string into an array of values, transforming each value. An empty array is returned for nulls or empty
164
- * strings
165
- * @param string
166
- * @param separator
167
- */
168
- function splitVal(string, separator, transform) {
169
- var val, i, l;
170
- if (string === null || string.length < 1) return [];
171
- val = string.split(separator);
172
- for (i = 0, l = val.length; i < l; i = i + 1) val[i] = transform(val[i]);
173
- return val;
174
- }
175
-
176
- function getSideBorderPadding(element) {
177
- return element.outerWidth(false) - element.width();
178
- }
179
-
180
- function installKeyUpChangeEvent(element) {
181
- var key="keyup-change-value";
182
- element.on("keydown", function () {
183
- if ($.data(element, key) === undefined) {
184
- $.data(element, key, element.val());
185
- }
186
- });
187
- element.on("keyup", function () {
188
- var val= $.data(element, key);
189
- if (val !== undefined && element.val() !== val) {
190
- $.removeData(element, key);
191
- element.trigger("keyup-change");
192
- }
193
- });
194
- }
195
-
196
-
197
- /**
198
- * filters mouse events so an event is fired only if the mouse moved.
199
- *
200
- * filters out mouse events that occur when mouse is stationary but
201
- * the elements under the pointer are scrolled.
202
- */
203
- function installFilteredMouseMove(element) {
204
- element.on("mousemove", function (e) {
205
- var lastpos = lastMousePosition;
206
- if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) {
207
- $(e.target).trigger("mousemove-filtered", e);
208
- }
209
- });
210
- }
211
-
212
- /**
213
- * Debounces a function. Returns a function that calls the original fn function only if no invocations have been made
214
- * within the last quietMillis milliseconds.
215
- *
216
- * @param quietMillis number of milliseconds to wait before invoking fn
217
- * @param fn function to be debounced
218
- * @param ctx object to be used as this reference within fn
219
- * @return debounced version of fn
220
- */
221
- function debounce(quietMillis, fn, ctx) {
222
- ctx = ctx || undefined;
223
- var timeout;
224
- return function () {
225
- var args = arguments;
226
- window.clearTimeout(timeout);
227
- timeout = window.setTimeout(function() {
228
- fn.apply(ctx, args);
229
- }, quietMillis);
230
- };
231
- }
232
-
233
- function installDebouncedScroll(threshold, element) {
234
- var notify = debounce(threshold, function (e) { element.trigger("scroll-debounced", e);});
235
- element.on("scroll", function (e) {
236
- if (indexOf(e.target, element.get()) >= 0) notify(e);
237
- });
238
- }
239
-
240
- function focus($el) {
241
- if ($el[0] === document.activeElement) return;
242
-
243
- /* set the focus in a 0 timeout - that way the focus is set after the processing
244
- of the current event has finished - which seems like the only reliable way
245
- to set focus */
246
- window.setTimeout(function() {
247
- var el=$el[0], pos=$el.val().length, range;
248
-
249
- $el.focus();
250
-
251
- /* make sure el received focus so we do not error out when trying to manipulate the caret.
252
- sometimes modals or others listeners may steal it after its set */
253
- var isVisible = (el.offsetWidth > 0 || el.offsetHeight > 0);
254
- if (isVisible && el === document.activeElement) {
255
-
256
- /* after the focus is set move the caret to the end, necessary when we val()
257
- just before setting focus */
258
- if(el.setSelectionRange)
259
- {
260
- el.setSelectionRange(pos, pos);
261
- }
262
- else if (el.createTextRange) {
263
- range = el.createTextRange();
264
- range.collapse(false);
265
- range.select();
266
- }
267
- }
268
- }, 0);
269
- }
270
-
271
- function getCursorInfo(el) {
272
- el = $(el)[0];
273
- var offset = 0;
274
- var length = 0;
275
- if ('selectionStart' in el) {
276
- offset = el.selectionStart;
277
- length = el.selectionEnd - offset;
278
- } else if ('selection' in document) {
279
- el.focus();
280
- var sel = document.selection.createRange();
281
- length = document.selection.createRange().text.length;
282
- sel.moveStart('character', -el.value.length);
283
- offset = sel.text.length - length;
284
- }
285
- return { offset: offset, length: length };
286
- }
287
-
288
- function killEvent(event) {
289
- event.preventDefault();
290
- event.stopPropagation();
291
- }
292
- function killEventImmediately(event) {
293
- event.preventDefault();
294
- event.stopImmediatePropagation();
295
- }
296
-
297
- function measureTextWidth(e) {
298
- if (!sizer){
299
- var style = e[0].currentStyle || window.getComputedStyle(e[0], null);
300
- sizer = $(document.createElement("div")).css({
301
- position: "absolute",
302
- left: "-10000px",
303
- top: "-10000px",
304
- display: "none",
305
- fontSize: style.fontSize,
306
- fontFamily: style.fontFamily,
307
- fontStyle: style.fontStyle,
308
- fontWeight: style.fontWeight,
309
- letterSpacing: style.letterSpacing,
310
- textTransform: style.textTransform,
311
- whiteSpace: "nowrap"
312
- });
313
- sizer.attr("class","select2-sizer");
314
- $(document.body).append(sizer);
315
- }
316
- sizer.text(e.val());
317
- return sizer.width();
318
- }
319
-
320
- function syncCssClasses(dest, src, adapter) {
321
- var classes, replacements = [], adapted;
322
-
323
- classes = $.trim(dest.attr("class"));
324
-
325
- if (classes) {
326
- classes = '' + classes; // for IE which returns object
327
-
328
- $(classes.split(/\s+/)).each2(function() {
329
- if (this.indexOf("select2-") === 0) {
330
- replacements.push(this);
331
- }
332
- });
333
- }
334
-
335
- classes = $.trim(src.attr("class"));
336
-
337
- if (classes) {
338
- classes = '' + classes; // for IE which returns object
339
-
340
- $(classes.split(/\s+/)).each2(function() {
341
- if (this.indexOf("select2-") !== 0) {
342
- adapted = adapter(this);
343
-
344
- if (adapted) {
345
- replacements.push(adapted);
346
- }
347
- }
348
- });
349
- }
350
-
351
- dest.attr("class", replacements.join(" "));
352
- }
353
-
354
-
355
- function markMatch(text, term, markup, escapeMarkup) {
356
- var match=stripDiacritics(text.toUpperCase()).indexOf(stripDiacritics(term.toUpperCase())),
357
- tl=term.length;
358
-
359
- if (match<0) {
360
- markup.push(escapeMarkup(text));
361
- return;
362
- }
363
-
364
- markup.push(escapeMarkup(text.substring(0, match)));
365
- markup.push("<span class='select2-match'>");
366
- markup.push(escapeMarkup(text.substring(match, match + tl)));
367
- markup.push("</span>");
368
- markup.push(escapeMarkup(text.substring(match + tl, text.length)));
369
- }
370
-
371
- function defaultEscapeMarkup(markup) {
372
- var replace_map = {
373
- '\\': '&#92;',
374
- '&': '&amp;',
375
- '<': '&lt;',
376
- '>': '&gt;',
377
- '"': '&quot;',
378
- "'": '&#39;',
379
- "/": '&#47;'
380
- };
381
-
382
- return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
383
- return replace_map[match];
384
- });
385
- }
386
-
387
- /**
388
- * Produces an ajax-based query function
389
- *
390
- * @param options object containing configuration parameters
391
- * @param options.params parameter map for the transport ajax call, can contain such options as cache, jsonpCallback, etc. see $.ajax
392
- * @param options.transport function that will be used to execute the ajax request. must be compatible with parameters supported by $.ajax
393
- * @param options.url url for the data
394
- * @param options.data a function(searchTerm, pageNumber, context) that should return an object containing query string parameters for the above url.
395
- * @param options.dataType request data type: ajax, jsonp, other datatypes supported by jQuery's $.ajax function or the transport function if specified
396
- * @param options.quietMillis (optional) milliseconds to wait before making the ajaxRequest, helps debounce the ajax function if invoked too often
397
- * @param options.results a function(remoteData, pageNumber, query) that converts data returned form the remote request to the format expected by Select2.
398
- * The expected format is an object containing the following keys:
399
- * results array of objects that will be used as choices
400
- * more (optional) boolean indicating whether there are more results available
401
- * Example: {results:[{id:1, text:'Red'},{id:2, text:'Blue'}], more:true}
402
- */
403
- function ajax(options) {
404
- var timeout, // current scheduled but not yet executed request
405
- handler = null,
406
- quietMillis = options.quietMillis || 100,
407
- ajaxUrl = options.url,
408
- self = this;
409
-
410
- return function (query) {
411
- window.clearTimeout(timeout);
412
- timeout = window.setTimeout(function () {
413
- var data = options.data, // ajax data function
414
- url = ajaxUrl, // ajax url string or function
415
- transport = options.transport || $.fn.select2.ajaxDefaults.transport,
416
- // deprecated - to be removed in 4.0 - use params instead
417
- deprecated = {
418
- type: options.type || 'GET', // set type of request (GET or POST)
419
- cache: options.cache || false,
420
- jsonpCallback: options.jsonpCallback||undefined,
421
- dataType: options.dataType||"json"
422
- },
423
- params = $.extend({}, $.fn.select2.ajaxDefaults.params, deprecated);
424
-
425
- data = data ? data.call(self, query.term, query.page, query.context) : null;
426
- url = (typeof url === 'function') ? url.call(self, query.term, query.page, query.context) : url;
427
-
428
- if (handler && typeof handler.abort === "function") { handler.abort(); }
429
-
430
- if (options.params) {
431
- if ($.isFunction(options.params)) {
432
- $.extend(params, options.params.call(self));
433
- } else {
434
- $.extend(params, options.params);
435
- }
436
- }
437
-
438
- $.extend(params, {
439
- url: url,
440
- dataType: options.dataType,
441
- data: data,
442
- success: function (data) {
443
- // TODO - replace query.page with query so users have access to term, page, etc.
444
- // added query as third paramter to keep backwards compatibility
445
- var results = options.results(data, query.page, query);
446
- query.callback(results);
447
- },
448
- error: function(jqXHR, textStatus, errorThrown){
449
- var results = {
450
- hasError: true,
451
- jqXHR: jqXHR,
452
- textStatus: textStatus,
453
- errorThrown: errorThrown
454
- };
455
-
456
- query.callback(results);
457
- }
458
- });
459
- handler = transport.call(self, params);
460
- }, quietMillis);
461
- };
462
- }
463
-
464
- /**
465
- * Produces a query function that works with a local array
466
- *
467
- * @param options object containing configuration parameters. The options parameter can either be an array or an
468
- * object.
469
- *
470
- * If the array form is used it is assumed that it contains objects with 'id' and 'text' keys.
471
- *
472
- * If the object form is used it is assumed that it contains 'data' and 'text' keys. The 'data' key should contain
473
- * an array of objects that will be used as choices. These objects must contain at least an 'id' key. The 'text'
474
- * key can either be a String in which case it is expected that each element in the 'data' array has a key with the
475
- * value of 'text' which will be used to match choices. Alternatively, text can be a function(item) that can extract
476
- * the text.
477
- */
478
- function local(options) {
479
- var data = options, // data elements
480
- dataText,
481
- tmp,
482
- text = function (item) { return ""+item.text; }; // function used to retrieve the text portion of a data item that is matched against the search
483
-
484
- if ($.isArray(data)) {
485
- tmp = data;
486
- data = { results: tmp };
487
- }
488
-
489
- if ($.isFunction(data) === false) {
490
- tmp = data;
491
- data = function() { return tmp; };
492
- }
493
-
494
- var dataItem = data();
495
- if (dataItem.text) {
496
- text = dataItem.text;
497
- // if text is not a function we assume it to be a key name
498
- if (!$.isFunction(text)) {
499
- dataText = dataItem.text; // we need to store this in a separate variable because in the next step data gets reset and data.text is no longer available
500
- text = function (item) { return item[dataText]; };
501
- }
502
- }
503
-
504
- return function (query) {
505
- var t = query.term, filtered = { results: [] }, process;
506
- if (t === "") {
507
- query.callback(data());
508
- return;
509
- }
510
-
511
- process = function(datum, collection) {
512
- var group, attr;
513
- datum = datum[0];
514
- if (datum.children) {
515
- group = {};
516
- for (attr in datum) {
517
- if (datum.hasOwnProperty(attr)) group[attr]=datum[attr];
518
- }
519
- group.children=[];
520
- $(datum.children).each2(function(i, childDatum) { process(childDatum, group.children); });
521
- if (group.children.length || query.matcher(t, text(group), datum)) {
522
- collection.push(group);
523
- }
524
- } else {
525
- if (query.matcher(t, text(datum), datum)) {
526
- collection.push(datum);
527
- }
528
- }
529
- };
530
-
531
- $(data().results).each2(function(i, datum) { process(datum, filtered.results); });
532
- query.callback(filtered);
533
- };
534
- }
535
-
536
- // TODO javadoc
537
- function tags(data) {
538
- var isFunc = $.isFunction(data);
539
- return function (query) {
540
- var t = query.term, filtered = {results: []};
541
- var result = isFunc ? data(query) : data;
542
- if ($.isArray(result)) {
543
- $(result).each(function () {
544
- var isObject = this.text !== undefined,
545
- text = isObject ? this.text : this;
546
- if (t === "" || query.matcher(t, text)) {
547
- filtered.results.push(isObject ? this : {id: this, text: this});
548
- }
549
- });
550
- query.callback(filtered);
551
- }
552
- };
553
- }
554
-
555
- /**
556
- * Checks if the formatter function should be used.
557
- *
558
- * Throws an error if it is not a function. Returns true if it should be used,
559
- * false if no formatting should be performed.
560
- *
561
- * @param formatter
562
- */
563
- function checkFormatter(formatter, formatterName) {
564
- if ($.isFunction(formatter)) return true;
565
- if (!formatter) return false;
566
- if (typeof(formatter) === 'string') return true;
567
- throw new Error(formatterName +" must be a string, function, or falsy value");
568
- }
569
-
570
- /**
571
- * Returns a given value
572
- * If given a function, returns its output
573
- *
574
- * @param val string|function
575
- * @param context value of "this" to be passed to function
576
- * @returns {*}
577
- */
578
- function evaluate(val, context) {
579
- if ($.isFunction(val)) {
580
- var args = Array.prototype.slice.call(arguments, 2);
581
- return val.apply(context, args);
582
- }
583
- return val;
584
- }
585
-
586
- function countResults(results) {
587
- var count = 0;
588
- $.each(results, function(i, item) {
589
- if (item.children) {
590
- count += countResults(item.children);
591
- } else {
592
- count++;
593
- }
594
- });
595
- return count;
596
- }
597
-
598
- /**
599
- * Default tokenizer. This function uses breaks the input on substring match of any string from the
600
- * opts.tokenSeparators array and uses opts.createSearchChoice to create the choice object. Both of those
601
- * two options have to be defined in order for the tokenizer to work.
602
- *
603
- * @param input text user has typed so far or pasted into the search field
604
- * @param selection currently selected choices
605
- * @param selectCallback function(choice) callback tho add the choice to selection
606
- * @param opts select2's opts
607
- * @return undefined/null to leave the current input unchanged, or a string to change the input to the returned value
608
- */
609
- function defaultTokenizer(input, selection, selectCallback, opts) {
610
- var original = input, // store the original so we can compare and know if we need to tell the search to update its text
611
- dupe = false, // check for whether a token we extracted represents a duplicate selected choice
612
- token, // token
613
- index, // position at which the separator was found
614
- i, l, // looping variables
615
- separator; // the matched separator
616
-
617
- if (!opts.createSearchChoice || !opts.tokenSeparators || opts.tokenSeparators.length < 1) return undefined;
618
-
619
- while (true) {
620
- index = -1;
621
-
622
- for (i = 0, l = opts.tokenSeparators.length; i < l; i++) {
623
- separator = opts.tokenSeparators[i];
624
- index = input.indexOf(separator);
625
- if (index >= 0) break;
626
- }
627
-
628
- if (index < 0) break; // did not find any token separator in the input string, bail
629
-
630
- token = input.substring(0, index);
631
- input = input.substring(index + separator.length);
632
-
633
- if (token.length > 0) {
634
- token = opts.createSearchChoice.call(this, token, selection);
635
- if (token !== undefined && token !== null && opts.id(token) !== undefined && opts.id(token) !== null) {
636
- dupe = false;
637
- for (i = 0, l = selection.length; i < l; i++) {
638
- if (equal(opts.id(token), opts.id(selection[i]))) {
639
- dupe = true; break;
640
- }
641
- }
642
-
643
- if (!dupe) selectCallback(token);
644
- }
645
- }
646
- }
647
-
648
- if (original!==input) return input;
649
- }
650
-
651
- function cleanupJQueryElements() {
652
- var self = this;
653
-
654
- $.each(arguments, function (i, element) {
655
- self[element].remove();
656
- self[element] = null;
657
- });
658
- }
659
-
660
- /**
661
- * Creates a new class
662
- *
663
- * @param superClass
664
- * @param methods
665
- */
666
- function clazz(SuperClass, methods) {
667
- var constructor = function () {};
668
- constructor.prototype = new SuperClass;
669
- constructor.prototype.constructor = constructor;
670
- constructor.prototype.parent = SuperClass.prototype;
671
- constructor.prototype = $.extend(constructor.prototype, methods);
672
- return constructor;
673
- }
674
-
675
- AbstractSelect2 = clazz(Object, {
676
-
677
- // abstract
678
- bind: function (func) {
679
- var self = this;
680
- return function () {
681
- func.apply(self, arguments);
682
- };
683
- },
684
-
685
- // abstract
686
- init: function (opts) {
687
- var results, search, resultsSelector = ".select2-results";
688
-
689
- // prepare options
690
- this.opts = opts = this.prepareOpts(opts);
691
-
692
- this.id=opts.id;
693
-
694
- // destroy if called on an existing component
695
- if (opts.element.data("select2") !== undefined &&
696
- opts.element.data("select2") !== null) {
697
- opts.element.data("select2").destroy();
698
- }
699
-
700
- this.container = this.createContainer();
701
-
702
- this.liveRegion = $('.select2-hidden-accessible');
703
- if (this.liveRegion.length == 0) {
704
- this.liveRegion = $("<span>", {
705
- role: "status",
706
- "aria-live": "polite"
707
- })
708
- .addClass("select2-hidden-accessible")
709
- .appendTo(document.body);
710
- }
711
-
712
- this.containerId="s2id_"+(opts.element.attr("id") || "autogen"+nextUid());
713
- this.containerEventName= this.containerId
714
- .replace(/([.])/g, '_')
715
- .replace(/([;&,\-\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1');
716
- this.container.attr("id", this.containerId);
717
-
718
- this.container.attr("title", opts.element.attr("title"));
719
-
720
- this.body = $(document.body);
721
-
722
- syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
723
-
724
- this.container.attr("style", opts.element.attr("style"));
725
- this.container.css(evaluate(opts.containerCss, this.opts.element));
726
- this.container.addClass(evaluate(opts.containerCssClass, this.opts.element));
727
-
728
- this.elementTabIndex = this.opts.element.attr("tabindex");
729
-
730
- // swap container for the element
731
- this.opts.element
732
- .data("select2", this)
733
- .attr("tabindex", "-1")
734
- .before(this.container)
735
- .on("click.select2", killEvent); // do not leak click events
736
-
737
- this.container.data("select2", this);
738
-
739
- this.dropdown = this.container.find(".select2-drop");
740
-
741
- syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
742
-
743
- this.dropdown.addClass(evaluate(opts.dropdownCssClass, this.opts.element));
744
- this.dropdown.data("select2", this);
745
- this.dropdown.on("click", killEvent);
746
-
747
- this.results = results = this.container.find(resultsSelector);
748
- this.search = search = this.container.find("input.select2-input");
749
-
750
- this.queryCount = 0;
751
- this.resultsPage = 0;
752
- this.context = null;
753
-
754
- // initialize the container
755
- this.initContainer();
756
-
757
- this.container.on("click", killEvent);
758
-
759
- installFilteredMouseMove(this.results);
760
-
761
- this.dropdown.on("mousemove-filtered", resultsSelector, this.bind(this.highlightUnderEvent));
762
- this.dropdown.on("touchstart touchmove touchend", resultsSelector, this.bind(function (event) {
763
- this._touchEvent = true;
764
- this.highlightUnderEvent(event);
765
- }));
766
- this.dropdown.on("touchmove", resultsSelector, this.bind(this.touchMoved));
767
- this.dropdown.on("touchstart touchend", resultsSelector, this.bind(this.clearTouchMoved));
768
-
769
- // Waiting for a click event on touch devices to select option and hide dropdown
770
- // otherwise click will be triggered on an underlying element
771
- this.dropdown.on('click', this.bind(function (event) {
772
- if (this._touchEvent) {
773
- this._touchEvent = false;
774
- this.selectHighlighted();
775
- }
776
- }));
777
-
778
- installDebouncedScroll(80, this.results);
779
- this.dropdown.on("scroll-debounced", resultsSelector, this.bind(this.loadMoreIfNeeded));
780
-
781
- // do not propagate change event from the search field out of the component
782
- $(this.container).on("change", ".select2-input", function(e) {e.stopPropagation();});
783
- $(this.dropdown).on("change", ".select2-input", function(e) {e.stopPropagation();});
784
-
785
- // if jquery.mousewheel plugin is installed we can prevent out-of-bounds scrolling of results via mousewheel
786
- if ($.fn.mousewheel) {
787
- results.mousewheel(function (e, delta, deltaX, deltaY) {
788
- var top = results.scrollTop();
789
- if (deltaY > 0 && top - deltaY <= 0) {
790
- results.scrollTop(0);
791
- killEvent(e);
792
- } else if (deltaY < 0 && results.get(0).scrollHeight - results.scrollTop() + deltaY <= results.height()) {
793
- results.scrollTop(results.get(0).scrollHeight - results.height());
794
- killEvent(e);
795
- }
796
- });
797
- }
798
-
799
- installKeyUpChangeEvent(search);
800
- search.on("keyup-change input paste", this.bind(this.updateResults));
801
- search.on("focus", function () { search.addClass("select2-focused"); });
802
- search.on("blur", function () { search.removeClass("select2-focused");});
803
-
804
- this.dropdown.on("mouseup", resultsSelector, this.bind(function (e) {
805
- if ($(e.target).closest(".select2-result-selectable").length > 0) {
806
- this.highlightUnderEvent(e);
807
- this.selectHighlighted(e);
808
- }
809
- }));
810
-
811
- // trap all mouse events from leaving the dropdown. sometimes there may be a modal that is listening
812
- // for mouse events outside of itself so it can close itself. since the dropdown is now outside the select2's
813
- // dom it will trigger the popup close, which is not what we want
814
- // focusin can cause focus wars between modals and select2 since the dropdown is outside the modal.
815
- this.dropdown.on("click mouseup mousedown touchstart touchend focusin", function (e) { e.stopPropagation(); });
816
-
817
- this.nextSearchTerm = undefined;
818
-
819
- if ($.isFunction(this.opts.initSelection)) {
820
- // initialize selection based on the current value of the source element
821
- this.initSelection();
822
-
823
- // if the user has provided a function that can set selection based on the value of the source element
824
- // we monitor the change event on the element and trigger it, allowing for two way synchronization
825
- this.monitorSource();
826
- }
827
-
828
- if (opts.maximumInputLength !== null) {
829
- this.search.attr("maxlength", opts.maximumInputLength);
830
- }
831
-
832
- var disabled = opts.element.prop("disabled");
833
- if (disabled === undefined) disabled = false;
834
- this.enable(!disabled);
835
-
836
- var readonly = opts.element.prop("readonly");
837
- if (readonly === undefined) readonly = false;
838
- this.readonly(readonly);
839
-
840
- // Calculate size of scrollbar
841
- scrollBarDimensions = scrollBarDimensions || measureScrollbar();
842
-
843
- this.autofocus = opts.element.prop("autofocus");
844
- opts.element.prop("autofocus", false);
845
- if (this.autofocus) this.focus();
846
-
847
- this.search.attr("placeholder", opts.searchInputPlaceholder);
848
- },
849
-
850
- // abstract
851
- destroy: function () {
852
- var element=this.opts.element, select2 = element.data("select2"), self = this;
853
-
854
- this.close();
855
-
856
- if (element.length && element[0].detachEvent && self._sync) {
857
- element.each(function () {
858
- if (self._sync) {
859
- this.detachEvent("onpropertychange", self._sync);
860
- }
861
- });
862
- }
863
- if (this.propertyObserver) {
864
- this.propertyObserver.disconnect();
865
- this.propertyObserver = null;
866
- }
867
- this._sync = null;
868
-
869
- if (select2 !== undefined) {
870
- select2.container.remove();
871
- select2.liveRegion.remove();
872
- select2.dropdown.remove();
873
- element
874
- .show()
875
- .removeData("select2")
876
- .off(".select2")
877
- .prop("autofocus", this.autofocus || false);
878
- if (this.elementTabIndex) {
879
- element.attr({tabindex: this.elementTabIndex});
880
- } else {
881
- element.removeAttr("tabindex");
882
- }
883
- element.show();
884
- }
885
-
886
- cleanupJQueryElements.call(this,
887
- "container",
888
- "liveRegion",
889
- "dropdown",
890
- "results",
891
- "search"
892
- );
893
- },
894
-
895
- // abstract
896
- optionToData: function(element) {
897
- if (element.is("option")) {
898
- return {
899
- id:element.prop("value"),
900
- text:element.text(),
901
- element: element.get(),
902
- css: element.attr("class"),
903
- disabled: element.prop("disabled"),
904
- locked: equal(element.attr("locked"), "locked") || equal(element.data("locked"), true)
905
- };
906
- } else if (element.is("optgroup")) {
907
- return {
908
- text:element.attr("label"),
909
- children:[],
910
- element: element.get(),
911
- css: element.attr("class")
912
- };
913
- }
914
- },
915
-
916
- // abstract
917
- prepareOpts: function (opts) {
918
- var element, select, idKey, ajaxUrl, self = this;
919
-
920
- element = opts.element;
921
-
922
- if (element.get(0).tagName.toLowerCase() === "select") {
923
- this.select = select = opts.element;
924
- }
925
-
926
- if (select) {
927
- // these options are not allowed when attached to a select because they are picked up off the element itself
928
- $.each(["id", "multiple", "ajax", "query", "createSearchChoice", "initSelection", "data", "tags"], function () {
929
- if (this in opts) {
930
- throw new Error("Option '" + this + "' is not allowed for Select2 when attached to a <select> element.");
931
- }
932
- });
933
- }
934
-
935
- opts = $.extend({}, {
936
- populateResults: function(container, results, query) {
937
- var populate, id=this.opts.id, liveRegion=this.liveRegion;
938
-
939
- populate=function(results, container, depth) {
940
-
941
- var i, l, result, selectable, disabled, compound, node, label, innerContainer, formatted;
942
-
943
- results = opts.sortResults(results, container, query);
944
-
945
- // collect the created nodes for bulk append
946
- var nodes = [];
947
- for (i = 0, l = results.length; i < l; i = i + 1) {
948
-
949
- result=results[i];
950
-
951
- disabled = (result.disabled === true);
952
- selectable = (!disabled) && (id(result) !== undefined);
953
-
954
- compound=result.children && result.children.length > 0;
955
-
956
- node=$("<li></li>");
957
- node.addClass("select2-results-dept-"+depth);
958
- node.addClass("select2-result");
959
- node.addClass(selectable ? "select2-result-selectable" : "select2-result-unselectable");
960
- if (disabled) { node.addClass("select2-disabled"); }
961
- if (compound) { node.addClass("select2-result-with-children"); }
962
- node.addClass(self.opts.formatResultCssClass(result));
963
- node.attr("role", "presentation");
964
-
965
- label=$(document.createElement("div"));
966
- label.addClass("select2-result-label");
967
- label.attr("id", "select2-result-label-" + nextUid());
968
- label.attr("role", "option");
969
-
970
- formatted=opts.formatResult(result, label, query, self.opts.escapeMarkup);
971
- if (formatted!==undefined) {
972
- label.html(formatted);
973
- node.append(label);
974
- }
975
-
976
-
977
- if (compound) {
978
-
979
- innerContainer=$("<ul></ul>");
980
- innerContainer.addClass("select2-result-sub");
981
- populate(result.children, innerContainer, depth+1);
982
- node.append(innerContainer);
983
- }
984
-
985
- node.data("select2-data", result);
986
- nodes.push(node[0]);
987
- }
988
-
989
- // bulk append the created nodes
990
- container.append(nodes);
991
- liveRegion.text(opts.formatMatches(results.length));
992
- };
993
-
994
- populate(results, container, 0);
995
- }
996
- }, $.fn.select2.defaults, opts);
997
-
998
- if (typeof(opts.id) !== "function") {
999
- idKey = opts.id;
1000
- opts.id = function (e) { return e[idKey]; };
1001
- }
1002
-
1003
- if ($.isArray(opts.element.data("select2Tags"))) {
1004
- if ("tags" in opts) {
1005
- throw "tags specified as both an attribute 'data-select2-tags' and in options of Select2 " + opts.element.attr("id");
1006
- }
1007
- opts.tags=opts.element.data("select2Tags");
1008
- }
1009
-
1010
- if (select) {
1011
- opts.query = this.bind(function (query) {
1012
- var data = { results: [], more: false },
1013
- term = query.term,
1014
- children, placeholderOption, process;
1015
-
1016
- process=function(element, collection) {
1017
- var group;
1018
- if (element.is("option")) {
1019
- if (query.matcher(term, element.text(), element)) {
1020
- collection.push(self.optionToData(element));
1021
- }
1022
- } else if (element.is("optgroup")) {
1023
- group=self.optionToData(element);
1024
- element.children().each2(function(i, elm) { process(elm, group.children); });
1025
- if (group.children.length>0) {
1026
- collection.push(group);
1027
- }
1028
- }
1029
- };
1030
-
1031
- children=element.children();
1032
-
1033
- // ignore the placeholder option if there is one
1034
- if (this.getPlaceholder() !== undefined && children.length > 0) {
1035
- placeholderOption = this.getPlaceholderOption();
1036
- if (placeholderOption) {
1037
- children=children.not(placeholderOption);
1038
- }
1039
- }
1040
-
1041
- children.each2(function(i, elm) { process(elm, data.results); });
1042
-
1043
- query.callback(data);
1044
- });
1045
- // this is needed because inside val() we construct choices from options and their id is hardcoded
1046
- opts.id=function(e) { return e.id; };
1047
- } else {
1048
- if (!("query" in opts)) {
1049
-
1050
- if ("ajax" in opts) {
1051
- ajaxUrl = opts.element.data("ajax-url");
1052
- if (ajaxUrl && ajaxUrl.length > 0) {
1053
- opts.ajax.url = ajaxUrl;
1054
- }
1055
- opts.query = ajax.call(opts.element, opts.ajax);
1056
- } else if ("data" in opts) {
1057
- opts.query = local(opts.data);
1058
- } else if ("tags" in opts) {
1059
- opts.query = tags(opts.tags);
1060
- if (opts.createSearchChoice === undefined) {
1061
- opts.createSearchChoice = function (term) { return {id: $.trim(term), text: $.trim(term)}; };
1062
- }
1063
- if (opts.initSelection === undefined) {
1064
- opts.initSelection = function (element, callback) {
1065
- var data = [];
1066
- $(splitVal(element.val(), opts.separator, opts.transformVal)).each(function () {
1067
- var obj = { id: this, text: this },
1068
- tags = opts.tags;
1069
- if ($.isFunction(tags)) tags=tags();
1070
- $(tags).each(function() { if (equal(this.id, obj.id)) { obj = this; return false; } });
1071
- data.push(obj);
1072
- });
1073
-
1074
- callback(data);
1075
- };
1076
- }
1077
- }
1078
- }
1079
- }
1080
- if (typeof(opts.query) !== "function") {
1081
- throw "query function not defined for Select2 " + opts.element.attr("id");
1082
- }
1083
-
1084
- if (opts.createSearchChoicePosition === 'top') {
1085
- opts.createSearchChoicePosition = function(list, item) { list.unshift(item); };
1086
- }
1087
- else if (opts.createSearchChoicePosition === 'bottom') {
1088
- opts.createSearchChoicePosition = function(list, item) { list.push(item); };
1089
- }
1090
- else if (typeof(opts.createSearchChoicePosition) !== "function") {
1091
- throw "invalid createSearchChoicePosition option must be 'top', 'bottom' or a custom function";
1092
- }
1093
-
1094
- return opts;
1095
- },
1096
-
1097
- /**
1098
- * Monitor the original element for changes and update select2 accordingly
1099
- */
1100
- // abstract
1101
- monitorSource: function () {
1102
- var el = this.opts.element, observer, self = this;
1103
-
1104
- el.on("change.select2", this.bind(function (e) {
1105
- if (this.opts.element.data("select2-change-triggered") !== true) {
1106
- this.initSelection();
1107
- }
1108
- }));
1109
-
1110
- this._sync = this.bind(function () {
1111
-
1112
- // sync enabled state
1113
- var disabled = el.prop("disabled");
1114
- if (disabled === undefined) disabled = false;
1115
- this.enable(!disabled);
1116
-
1117
- var readonly = el.prop("readonly");
1118
- if (readonly === undefined) readonly = false;
1119
- this.readonly(readonly);
1120
-
1121
- if (this.container) {
1122
- syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
1123
- this.container.addClass(evaluate(this.opts.containerCssClass, this.opts.element));
1124
- }
1125
-
1126
- if (this.dropdown) {
1127
- syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
1128
- this.dropdown.addClass(evaluate(this.opts.dropdownCssClass, this.opts.element));
1129
- }
1130
-
1131
- });
1132
-
1133
- // IE8-10 (IE9/10 won't fire propertyChange via attachEventListener)
1134
- if (el.length && el[0].attachEvent) {
1135
- el.each(function() {
1136
- this.attachEvent("onpropertychange", self._sync);
1137
- });
1138
- }
1139
-
1140
- // safari, chrome, firefox, IE11
1141
- observer = window.MutationObserver || window.WebKitMutationObserver|| window.MozMutationObserver;
1142
- if (observer !== undefined) {
1143
- if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; }
1144
- this.propertyObserver = new observer(function (mutations) {
1145
- $.each(mutations, self._sync);
1146
- });
1147
- this.propertyObserver.observe(el.get(0), { attributes:true, subtree:false });
1148
- }
1149
- },
1150
-
1151
- // abstract
1152
- triggerSelect: function(data) {
1153
- var evt = $.Event("select2-selecting", { val: this.id(data), object: data, choice: data });
1154
- this.opts.element.trigger(evt);
1155
- return !evt.isDefaultPrevented();
1156
- },
1157
-
1158
- /**
1159
- * Triggers the change event on the source element
1160
- */
1161
- // abstract
1162
- triggerChange: function (details) {
1163
-
1164
- details = details || {};
1165
- details= $.extend({}, details, { type: "change", val: this.val() });
1166
- // prevents recursive triggering
1167
- this.opts.element.data("select2-change-triggered", true);
1168
- this.opts.element.trigger(details);
1169
- this.opts.element.data("select2-change-triggered", false);
1170
-
1171
- // some validation frameworks ignore the change event and listen instead to keyup, click for selects
1172
- // so here we trigger the click event manually
1173
- this.opts.element.click();
1174
-
1175
- // ValidationEngine ignores the change event and listens instead to blur
1176
- // so here we trigger the blur event manually if so desired
1177
- if (this.opts.blurOnChange)
1178
- this.opts.element.blur();
1179
- },
1180
-
1181
- //abstract
1182
- isInterfaceEnabled: function()
1183
- {
1184
- return this.enabledInterface === true;
1185
- },
1186
-
1187
- // abstract
1188
- enableInterface: function() {
1189
- var enabled = this._enabled && !this._readonly,
1190
- disabled = !enabled;
1191
-
1192
- if (enabled === this.enabledInterface) return false;
1193
-
1194
- this.container.toggleClass("select2-container-disabled", disabled);
1195
- this.close();
1196
- this.enabledInterface = enabled;
1197
-
1198
- return true;
1199
- },
1200
-
1201
- // abstract
1202
- enable: function(enabled) {
1203
- if (enabled === undefined) enabled = true;
1204
- if (this._enabled === enabled) return;
1205
- this._enabled = enabled;
1206
-
1207
- this.opts.element.prop("disabled", !enabled);
1208
- this.enableInterface();
1209
- },
1210
-
1211
- // abstract
1212
- disable: function() {
1213
- this.enable(false);
1214
- },
1215
-
1216
- // abstract
1217
- readonly: function(enabled) {
1218
- if (enabled === undefined) enabled = false;
1219
- if (this._readonly === enabled) return;
1220
- this._readonly = enabled;
1221
-
1222
- this.opts.element.prop("readonly", enabled);
1223
- this.enableInterface();
1224
- },
1225
-
1226
- // abstract
1227
- opened: function () {
1228
- return (this.container) ? this.container.hasClass("select2-dropdown-open") : false;
1229
- },
1230
-
1231
- // abstract
1232
- positionDropdown: function() {
1233
- var $dropdown = this.dropdown,
1234
- container = this.container,
1235
- offset = container.offset(),
1236
- height = container.outerHeight(false),
1237
- width = container.outerWidth(false),
1238
- dropHeight = $dropdown.outerHeight(false),
1239
- $window = $(window),
1240
- windowWidth = $window.width(),
1241
- windowHeight = $window.height(),
1242
- viewPortRight = $window.scrollLeft() + windowWidth,
1243
- viewportBottom = $window.scrollTop() + windowHeight,
1244
- dropTop = offset.top + height,
1245
- dropLeft = offset.left,
1246
- enoughRoomBelow = dropTop + dropHeight <= viewportBottom,
1247
- enoughRoomAbove = (offset.top - dropHeight) >= $window.scrollTop(),
1248
- dropWidth = $dropdown.outerWidth(false),
1249
- enoughRoomOnRight = function() {
1250
- return dropLeft + dropWidth <= viewPortRight;
1251
- },
1252
- enoughRoomOnLeft = function() {
1253
- return offset.left + viewPortRight + container.outerWidth(false) > dropWidth;
1254
- },
1255
- aboveNow = $dropdown.hasClass("select2-drop-above"),
1256
- bodyOffset,
1257
- above,
1258
- changeDirection,
1259
- css,
1260
- resultsListNode;
1261
-
1262
- // always prefer the current above/below alignment, unless there is not enough room
1263
- if (aboveNow) {
1264
- above = true;
1265
- if (!enoughRoomAbove && enoughRoomBelow) {
1266
- changeDirection = true;
1267
- above = false;
1268
- }
1269
- } else {
1270
- above = false;
1271
- if (!enoughRoomBelow && enoughRoomAbove) {
1272
- changeDirection = true;
1273
- above = true;
1274
- }
1275
- }
1276
-
1277
- //if we are changing direction we need to get positions when dropdown is hidden;
1278
- if (changeDirection) {
1279
- $dropdown.hide();
1280
- offset = this.container.offset();
1281
- height = this.container.outerHeight(false);
1282
- width = this.container.outerWidth(false);
1283
- dropHeight = $dropdown.outerHeight(false);
1284
- viewPortRight = $window.scrollLeft() + windowWidth;
1285
- viewportBottom = $window.scrollTop() + windowHeight;
1286
- dropTop = offset.top + height;
1287
- dropLeft = offset.left;
1288
- dropWidth = $dropdown.outerWidth(false);
1289
- $dropdown.show();
1290
-
1291
- // fix so the cursor does not move to the left within the search-textbox in IE
1292
- this.focusSearch();
1293
- }
1294
-
1295
- if (this.opts.dropdownAutoWidth) {
1296
- resultsListNode = $('.select2-results', $dropdown)[0];
1297
- $dropdown.addClass('select2-drop-auto-width');
1298
- $dropdown.css('width', '');
1299
- // Add scrollbar width to dropdown if vertical scrollbar is present
1300
- dropWidth = $dropdown.outerWidth(false) + (resultsListNode.scrollHeight === resultsListNode.clientHeight ? 0 : scrollBarDimensions.width);
1301
- dropWidth > width ? width = dropWidth : dropWidth = width;
1302
- dropHeight = $dropdown.outerHeight(false);
1303
- }
1304
- else {
1305
- this.container.removeClass('select2-drop-auto-width');
1306
- }
1307
-
1308
- //console.log("below/ droptop:", dropTop, "dropHeight", dropHeight, "sum", (dropTop+dropHeight)+" viewport bottom", viewportBottom, "enough?", enoughRoomBelow);
1309
- //console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body.scrollTop(), "enough?", enoughRoomAbove);
1310
-
1311
- // fix positioning when body has an offset and is not position: static
1312
- if (this.body.css('position') !== 'static') {
1313
- bodyOffset = this.body.offset();
1314
- dropTop -= bodyOffset.top;
1315
- dropLeft -= bodyOffset.left;
1316
- }
1317
-
1318
- if (!enoughRoomOnRight() && enoughRoomOnLeft()) {
1319
- dropLeft = offset.left + this.container.outerWidth(false) - dropWidth;
1320
- }
1321
-
1322
- css = {
1323
- left: dropLeft,
1324
- width: width
1325
- };
1326
-
1327
- if (above) {
1328
- css.top = offset.top - dropHeight;
1329
- css.bottom = 'auto';
1330
- this.container.addClass("select2-drop-above");
1331
- $dropdown.addClass("select2-drop-above");
1332
- }
1333
- else {
1334
- css.top = dropTop;
1335
- css.bottom = 'auto';
1336
- this.container.removeClass("select2-drop-above");
1337
- $dropdown.removeClass("select2-drop-above");
1338
- }
1339
- css = $.extend(css, evaluate(this.opts.dropdownCss, this.opts.element));
1340
-
1341
- $dropdown.css(css);
1342
- },
1343
-
1344
- // abstract
1345
- shouldOpen: function() {
1346
- var event;
1347
-
1348
- if (this.opened()) return false;
1349
-
1350
- if (this._enabled === false || this._readonly === true) return false;
1351
-
1352
- event = $.Event("select2-opening");
1353
- this.opts.element.trigger(event);
1354
- return !event.isDefaultPrevented();
1355
- },
1356
-
1357
- // abstract
1358
- clearDropdownAlignmentPreference: function() {
1359
- // clear the classes used to figure out the preference of where the dropdown should be opened
1360
- this.container.removeClass("select2-drop-above");
1361
- this.dropdown.removeClass("select2-drop-above");
1362
- },
1363
-
1364
- /**
1365
- * Opens the dropdown
1366
- *
1367
- * @return {Boolean} whether or not dropdown was opened. This method will return false if, for example,
1368
- * the dropdown is already open, or if the 'open' event listener on the element called preventDefault().
1369
- */
1370
- // abstract
1371
- open: function () {
1372
-
1373
- if (!this.shouldOpen()) return false;
1374
-
1375
- this.opening();
1376
-
1377
- // Only bind the document mousemove when the dropdown is visible
1378
- $document.on("mousemove.select2Event", function (e) {
1379
- lastMousePosition.x = e.pageX;
1380
- lastMousePosition.y = e.pageY;
1381
- });
1382
-
1383
- return true;
1384
- },
1385
-
1386
- /**
1387
- * Performs the opening of the dropdown
1388
- */
1389
- // abstract
1390
- opening: function() {
1391
- var cid = this.containerEventName,
1392
- scroll = "scroll." + cid,
1393
- resize = "resize."+cid,
1394
- orient = "orientationchange."+cid,
1395
- mask;
1396
-
1397
- this.container.addClass("select2-dropdown-open").addClass("select2-container-active");
1398
-
1399
- this.clearDropdownAlignmentPreference();
1400
-
1401
- if(this.dropdown[0] !== this.body.children().last()[0]) {
1402
- this.dropdown.detach().appendTo(this.body);
1403
- }
1404
-
1405
- // create the dropdown mask if doesn't already exist
1406
- mask = $("#select2-drop-mask");
1407
- if (mask.length === 0) {
1408
- mask = $(document.createElement("div"));
1409
- mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask");
1410
- mask.hide();
1411
- mask.appendTo(this.body);
1412
- mask.on("mousedown touchstart click", function (e) {
1413
- // Prevent IE from generating a click event on the body
1414
- reinsertElement(mask);
1415
-
1416
- var dropdown = $("#select2-drop"), self;
1417
- if (dropdown.length > 0) {
1418
- self=dropdown.data("select2");
1419
- if (self.opts.selectOnBlur) {
1420
- self.selectHighlighted({noFocus: true});
1421
- }
1422
- self.close();
1423
- e.preventDefault();
1424
- e.stopPropagation();
1425
- }
1426
- });
1427
- }
1428
-
1429
- // ensure the mask is always right before the dropdown
1430
- if (this.dropdown.prev()[0] !== mask[0]) {
1431
- this.dropdown.before(mask);
1432
- }
1433
-
1434
- // move the global id to the correct dropdown
1435
- $("#select2-drop").removeAttr("id");
1436
- this.dropdown.attr("id", "select2-drop");
1437
-
1438
- // show the elements
1439
- mask.show();
1440
-
1441
- this.positionDropdown();
1442
- this.dropdown.show();
1443
- this.positionDropdown();
1444
-
1445
- this.dropdown.addClass("select2-drop-active");
1446
-
1447
- // attach listeners to events that can change the position of the container and thus require
1448
- // the position of the dropdown to be updated as well so it does not come unglued from the container
1449
- var that = this;
1450
- this.container.parents().add(window).each(function () {
1451
- $(this).on(resize+" "+scroll+" "+orient, function (e) {
1452
- if (that.opened()) that.positionDropdown();
1453
- });
1454
- });
1455
-
1456
-
1457
- },
1458
-
1459
- // abstract
1460
- close: function () {
1461
- if (!this.opened()) return;
1462
-
1463
- var cid = this.containerEventName,
1464
- scroll = "scroll." + cid,
1465
- resize = "resize."+cid,
1466
- orient = "orientationchange."+cid;
1467
-
1468
- // unbind event listeners
1469
- this.container.parents().add(window).each(function () { $(this).off(scroll).off(resize).off(orient); });
1470
-
1471
- this.clearDropdownAlignmentPreference();
1472
-
1473
- $("#select2-drop-mask").hide();
1474
- this.dropdown.removeAttr("id"); // only the active dropdown has the select2-drop id
1475
- this.dropdown.hide();
1476
- this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active");
1477
- this.results.empty();
1478
-
1479
- // Now that the dropdown is closed, unbind the global document mousemove event
1480
- $document.off("mousemove.select2Event");
1481
-
1482
- this.clearSearch();
1483
- this.search.removeClass("select2-active");
1484
- this.opts.element.trigger($.Event("select2-close"));
1485
- },
1486
-
1487
- /**
1488
- * Opens control, sets input value, and updates results.
1489
- */
1490
- // abstract
1491
- externalSearch: function (term) {
1492
- this.open();
1493
- this.search.val(term);
1494
- this.updateResults(false);
1495
- },
1496
-
1497
- // abstract
1498
- clearSearch: function () {
1499
-
1500
- },
1501
-
1502
- //abstract
1503
- getMaximumSelectionSize: function() {
1504
- return evaluate(this.opts.maximumSelectionSize, this.opts.element);
1505
- },
1506
-
1507
- // abstract
1508
- ensureHighlightVisible: function () {
1509
- var results = this.results, children, index, child, hb, rb, y, more, topOffset;
1510
-
1511
- index = this.highlight();
1512
-
1513
- if (index < 0) return;
1514
-
1515
- if (index == 0) {
1516
-
1517
- // if the first element is highlighted scroll all the way to the top,
1518
- // that way any unselectable headers above it will also be scrolled
1519
- // into view
1520
-
1521
- results.scrollTop(0);
1522
- return;
1523
- }
1524
-
1525
- children = this.findHighlightableChoices().find('.select2-result-label');
1526
-
1527
- child = $(children[index]);
1528
-
1529
- topOffset = (child.offset() || {}).top || 0;
1530
-
1531
- hb = topOffset + child.outerHeight(true);
1532
-
1533
- // if this is the last child lets also make sure select2-more-results is visible
1534
- if (index === children.length - 1) {
1535
- more = results.find("li.select2-more-results");
1536
- if (more.length > 0) {
1537
- hb = more.offset().top + more.outerHeight(true);
1538
- }
1539
- }
1540
-
1541
- rb = results.offset().top + results.outerHeight(false);
1542
- if (hb > rb) {
1543
- results.scrollTop(results.scrollTop() + (hb - rb));
1544
- }
1545
- y = topOffset - results.offset().top;
1546
-
1547
- // make sure the top of the element is visible
1548
- if (y < 0 && child.css('display') != 'none' ) {
1549
- results.scrollTop(results.scrollTop() + y); // y is negative
1550
- }
1551
- },
1552
-
1553
- // abstract
1554
- findHighlightableChoices: function() {
1555
- return this.results.find(".select2-result-selectable:not(.select2-disabled):not(.select2-selected)");
1556
- },
1557
-
1558
- // abstract
1559
- moveHighlight: function (delta) {
1560
- var choices = this.findHighlightableChoices(),
1561
- index = this.highlight();
1562
-
1563
- while (index > -1 && index < choices.length) {
1564
- index += delta;
1565
- var choice = $(choices[index]);
1566
- if (choice.hasClass("select2-result-selectable") && !choice.hasClass("select2-disabled") && !choice.hasClass("select2-selected")) {
1567
- this.highlight(index);
1568
- break;
1569
- }
1570
- }
1571
- },
1572
-
1573
- // abstract
1574
- highlight: function (index) {
1575
- var choices = this.findHighlightableChoices(),
1576
- choice,
1577
- data;
1578
-
1579
- if (arguments.length === 0) {
1580
- return indexOf(choices.filter(".select2-highlighted")[0], choices.get());
1581
- }
1582
-
1583
- if (index >= choices.length) index = choices.length - 1;
1584
- if (index < 0) index = 0;
1585
-
1586
- this.removeHighlight();
1587
-
1588
- choice = $(choices[index]);
1589
- choice.addClass("select2-highlighted");
1590
-
1591
- // ensure assistive technology can determine the active choice
1592
- this.search.attr("aria-activedescendant", choice.find(".select2-result-label").attr("id"));
1593
-
1594
- this.ensureHighlightVisible();
1595
-
1596
- this.liveRegion.text(choice.text());
1597
-
1598
- data = choice.data("select2-data");
1599
- if (data) {
1600
- this.opts.element.trigger({ type: "select2-highlight", val: this.id(data), choice: data });
1601
- }
1602
- },
1603
-
1604
- removeHighlight: function() {
1605
- this.results.find(".select2-highlighted").removeClass("select2-highlighted");
1606
- },
1607
-
1608
- touchMoved: function() {
1609
- this._touchMoved = true;
1610
- },
1611
-
1612
- clearTouchMoved: function() {
1613
- this._touchMoved = false;
1614
- },
1615
-
1616
- // abstract
1617
- countSelectableResults: function() {
1618
- return this.findHighlightableChoices().length;
1619
- },
1620
-
1621
- // abstract
1622
- highlightUnderEvent: function (event) {
1623
- var el = $(event.target).closest(".select2-result-selectable");
1624
- if (el.length > 0 && !el.is(".select2-highlighted")) {
1625
- var choices = this.findHighlightableChoices();
1626
- this.highlight(choices.index(el));
1627
- } else if (el.length == 0) {
1628
- // if we are over an unselectable item remove all highlights
1629
- this.removeHighlight();
1630
- }
1631
- },
1632
-
1633
- // abstract
1634
- loadMoreIfNeeded: function () {
1635
- var results = this.results,
1636
- more = results.find("li.select2-more-results"),
1637
- below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible
1638
- page = this.resultsPage + 1,
1639
- self=this,
1640
- term=this.search.val(),
1641
- context=this.context;
1642
-
1643
- if (more.length === 0) return;
1644
- below = more.offset().top - results.offset().top - results.height();
1645
-
1646
- if (below <= this.opts.loadMorePadding) {
1647
- more.addClass("select2-active");
1648
- this.opts.query({
1649
- element: this.opts.element,
1650
- term: term,
1651
- page: page,
1652
- context: context,
1653
- matcher: this.opts.matcher,
1654
- callback: this.bind(function (data) {
1655
-
1656
- // ignore a response if the select2 has been closed before it was received
1657
- if (!self.opened()) return;
1658
-
1659
-
1660
- self.opts.populateResults.call(this, results, data.results, {term: term, page: page, context:context});
1661
- self.postprocessResults(data, false, false);
1662
-
1663
- if (data.more===true) {
1664
- more.detach().appendTo(results).html(self.opts.escapeMarkup(evaluate(self.opts.formatLoadMore, self.opts.element, page+1)));
1665
- window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
1666
- } else {
1667
- more.remove();
1668
- }
1669
- self.positionDropdown();
1670
- self.resultsPage = page;
1671
- self.context = data.context;
1672
- this.opts.element.trigger({ type: "select2-loaded", items: data });
1673
- })});
1674
- }
1675
- },
1676
-
1677
- /**
1678
- * Default tokenizer function which does nothing
1679
- */
1680
- tokenize: function() {
1681
-
1682
- },
1683
-
1684
- /**
1685
- * @param initial whether or not this is the call to this method right after the dropdown has been opened
1686
- */
1687
- // abstract
1688
- updateResults: function (initial) {
1689
- var search = this.search,
1690
- results = this.results,
1691
- opts = this.opts,
1692
- data,
1693
- self = this,
1694
- input,
1695
- term = search.val(),
1696
- lastTerm = $.data(this.container, "select2-last-term"),
1697
- // sequence number used to drop out-of-order responses
1698
- queryNumber;
1699
-
1700
- // prevent duplicate queries against the same term
1701
- if (initial !== true && lastTerm && equal(term, lastTerm)) return;
1702
-
1703
- $.data(this.container, "select2-last-term", term);
1704
-
1705
- // if the search is currently hidden we do not alter the results
1706
- if (initial !== true && (this.showSearchInput === false || !this.opened())) {
1707
- return;
1708
- }
1709
-
1710
- function postRender() {
1711
- search.removeClass("select2-active");
1712
- self.positionDropdown();
1713
- if (results.find('.select2-no-results,.select2-selection-limit,.select2-searching').length) {
1714
- self.liveRegion.text(results.text());
1715
- }
1716
- else {
1717
- self.liveRegion.text(self.opts.formatMatches(results.find('.select2-result-selectable:not(".select2-selected")').length));
1718
- }
1719
- }
1720
-
1721
- function render(html) {
1722
- results.html(html);
1723
- postRender();
1724
- }
1725
-
1726
- queryNumber = ++this.queryCount;
1727
-
1728
- var maxSelSize = this.getMaximumSelectionSize();
1729
- if (maxSelSize >=1) {
1730
- data = this.data();
1731
- if ($.isArray(data) && data.length >= maxSelSize && checkFormatter(opts.formatSelectionTooBig, "formatSelectionTooBig")) {
1732
- render("<li class='select2-selection-limit'>" + evaluate(opts.formatSelectionTooBig, opts.element, maxSelSize) + "</li>");
1733
- return;
1734
- }
1735
- }
1736
-
1737
- if (search.val().length < opts.minimumInputLength) {
1738
- if (checkFormatter(opts.formatInputTooShort, "formatInputTooShort")) {
1739
- render("<li class='select2-no-results'>" + evaluate(opts.formatInputTooShort, opts.element, search.val(), opts.minimumInputLength) + "</li>");
1740
- } else {
1741
- render("");
1742
- }
1743
- if (initial && this.showSearch) this.showSearch(true);
1744
- return;
1745
- }
1746
-
1747
- if (opts.maximumInputLength && search.val().length > opts.maximumInputLength) {
1748
- if (checkFormatter(opts.formatInputTooLong, "formatInputTooLong")) {
1749
- render("<li class='select2-no-results'>" + evaluate(opts.formatInputTooLong, opts.element, search.val(), opts.maximumInputLength) + "</li>");
1750
- } else {
1751
- render("");
1752
- }
1753
- return;
1754
- }
1755
-
1756
- if (opts.formatSearching && this.findHighlightableChoices().length === 0) {
1757
- render("<li class='select2-searching'>" + evaluate(opts.formatSearching, opts.element) + "</li>");
1758
- }
1759
-
1760
- search.addClass("select2-active");
1761
-
1762
- this.removeHighlight();
1763
-
1764
- // give the tokenizer a chance to pre-process the input
1765
- input = this.tokenize();
1766
- if (input != undefined && input != null) {
1767
- search.val(input);
1768
- }
1769
-
1770
- this.resultsPage = 1;
1771
-
1772
- opts.query({
1773
- element: opts.element,
1774
- term: search.val(),
1775
- page: this.resultsPage,
1776
- context: null,
1777
- matcher: opts.matcher,
1778
- callback: this.bind(function (data) {
1779
- var def; // default choice
1780
-
1781
- // ignore old responses
1782
- if (queryNumber != this.queryCount) {
1783
- return;
1784
- }
1785
-
1786
- // ignore a response if the select2 has been closed before it was received
1787
- if (!this.opened()) {
1788
- this.search.removeClass("select2-active");
1789
- return;
1790
- }
1791
-
1792
- // handle ajax error
1793
- if(data.hasError !== undefined && checkFormatter(opts.formatAjaxError, "formatAjaxError")) {
1794
- render("<li class='select2-ajax-error'>" + evaluate(opts.formatAjaxError, opts.element, data.jqXHR, data.textStatus, data.errorThrown) + "</li>");
1795
- return;
1796
- }
1797
-
1798
- // save context, if any
1799
- this.context = (data.context===undefined) ? null : data.context;
1800
- // create a default choice and prepend it to the list
1801
- if (this.opts.createSearchChoice && search.val() !== "") {
1802
- def = this.opts.createSearchChoice.call(self, search.val(), data.results);
1803
- if (def !== undefined && def !== null && self.id(def) !== undefined && self.id(def) !== null) {
1804
- if ($(data.results).filter(
1805
- function () {
1806
- return equal(self.id(this), self.id(def));
1807
- }).length === 0) {
1808
- this.opts.createSearchChoicePosition(data.results, def);
1809
- }
1810
- }
1811
- }
1812
-
1813
- if (data.results.length === 0 && checkFormatter(opts.formatNoMatches, "formatNoMatches")) {
1814
- render("<li class='select2-no-results'>" + evaluate(opts.formatNoMatches, opts.element, search.val()) + "</li>");
1815
- return;
1816
- }
1817
-
1818
- results.empty();
1819
- self.opts.populateResults.call(this, results, data.results, {term: search.val(), page: this.resultsPage, context:null});
1820
-
1821
- if (data.more === true && checkFormatter(opts.formatLoadMore, "formatLoadMore")) {
1822
- results.append("<li class='select2-more-results'>" + opts.escapeMarkup(evaluate(opts.formatLoadMore, opts.element, this.resultsPage)) + "</li>");
1823
- window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
1824
- }
1825
-
1826
- this.postprocessResults(data, initial);
1827
-
1828
- postRender();
1829
-
1830
- this.opts.element.trigger({ type: "select2-loaded", items: data });
1831
- })});
1832
- },
1833
-
1834
- // abstract
1835
- cancel: function () {
1836
- this.close();
1837
- },
1838
-
1839
- // abstract
1840
- blur: function () {
1841
- // if selectOnBlur == true, select the currently highlighted option
1842
- if (this.opts.selectOnBlur)
1843
- this.selectHighlighted({noFocus: true});
1844
-
1845
- this.close();
1846
- this.container.removeClass("select2-container-active");
1847
- // synonymous to .is(':focus'), which is available in jquery >= 1.6
1848
- if (this.search[0] === document.activeElement) { this.search.blur(); }
1849
- this.clearSearch();
1850
- this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
1851
- },
1852
-
1853
- // abstract
1854
- focusSearch: function () {
1855
- focus(this.search);
1856
- },
1857
-
1858
- // abstract
1859
- selectHighlighted: function (options) {
1860
- if (this._touchMoved) {
1861
- this.clearTouchMoved();
1862
- return;
1863
- }
1864
- var index=this.highlight(),
1865
- highlighted=this.results.find(".select2-highlighted"),
1866
- data = highlighted.closest('.select2-result').data("select2-data");
1867
-
1868
- if (data) {
1869
- this.highlight(index);
1870
- this.onSelect(data, options);
1871
- } else if (options && options.noFocus) {
1872
- this.close();
1873
- }
1874
- },
1875
-
1876
- // abstract
1877
- getPlaceholder: function () {
1878
- var placeholderOption;
1879
- return this.opts.element.attr("placeholder") ||
1880
- this.opts.element.attr("data-placeholder") || // jquery 1.4 compat
1881
- this.opts.element.data("placeholder") ||
1882
- this.opts.placeholder ||
1883
- ((placeholderOption = this.getPlaceholderOption()) !== undefined ? placeholderOption.text() : undefined);
1884
- },
1885
-
1886
- // abstract
1887
- getPlaceholderOption: function() {
1888
- if (this.select) {
1889
- var firstOption = this.select.children('option').first();
1890
- if (this.opts.placeholderOption !== undefined ) {
1891
- //Determine the placeholder option based on the specified placeholderOption setting
1892
- return (this.opts.placeholderOption === "first" && firstOption) ||
1893
- (typeof this.opts.placeholderOption === "function" && this.opts.placeholderOption(this.select));
1894
- } else if ($.trim(firstOption.text()) === "" && firstOption.val() === "") {
1895
- //No explicit placeholder option specified, use the first if it's blank
1896
- return firstOption;
1897
- }
1898
- }
1899
- },
1900
-
1901
- /**
1902
- * Get the desired width for the container element. This is
1903
- * derived first from option `width` passed to select2, then
1904
- * the inline 'style' on the original element, and finally
1905
- * falls back to the jQuery calculated element width.
1906
- */
1907
- // abstract
1908
- initContainerWidth: function () {
1909
- function resolveContainerWidth() {
1910
- var style, attrs, matches, i, l, attr;
1911
-
1912
- if (this.opts.width === "off") {
1913
- return null;
1914
- } else if (this.opts.width === "element"){
1915
- return this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px';
1916
- } else if (this.opts.width === "copy" || this.opts.width === "resolve") {
1917
- // check if there is inline style on the element that contains width
1918
- style = this.opts.element.attr('style');
1919
- if (style !== undefined) {
1920
- attrs = style.split(';');
1921
- for (i = 0, l = attrs.length; i < l; i = i + 1) {
1922
- attr = attrs[i].replace(/\s/g, '');
1923
- matches = attr.match(/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i);
1924
- if (matches !== null && matches.length >= 1)
1925
- return matches[1];
1926
- }
1927
- }
1928
-
1929
- if (this.opts.width === "resolve") {
1930
- // next check if css('width') can resolve a width that is percent based, this is sometimes possible
1931
- // when attached to input type=hidden or elements hidden via css
1932
- style = this.opts.element.css('width');
1933
- if (style.indexOf("%") > 0) return style;
1934
-
1935
- // finally, fallback on the calculated width of the element
1936
- return (this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px');
1937
- }
1938
-
1939
- return null;
1940
- } else if ($.isFunction(this.opts.width)) {
1941
- return this.opts.width();
1942
- } else {
1943
- return this.opts.width;
1944
- }
1945
- };
1946
-
1947
- var width = resolveContainerWidth.call(this);
1948
- if (width !== null) {
1949
- this.container.css("width", width);
1950
- }
1951
- }
1952
- });
1953
-
1954
- SingleSelect2 = clazz(AbstractSelect2, {
1955
-
1956
- // single
1957
-
1958
- createContainer: function () {
1959
- var container = $(document.createElement("div")).attr({
1960
- "class": "select2-container"
1961
- }).html([
1962
- "<a href='javascript:void(0)' class='select2-choice' tabindex='-1'>",
1963
- " <span class='select2-chosen'>&#160;</span><abbr class='select2-search-choice-close'></abbr>",
1964
- " <span class='select2-arrow' role='presentation'><b role='presentation'></b></span>",
1965
- "</a>",
1966
- "<label for='' class='select2-offscreen'></label>",
1967
- "<input class='select2-focusser select2-offscreen' type='text' aria-haspopup='true' role='button' />",
1968
- "<div class='select2-drop select2-display-none'>",
1969
- " <div class='select2-search'>",
1970
- " <label for='' class='select2-offscreen'></label>",
1971
- " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input' role='combobox' aria-expanded='true'",
1972
- " aria-autocomplete='list' />",
1973
- " </div>",
1974
- " <ul class='select2-results' role='listbox'>",
1975
- " </ul>",
1976
- "</div>"].join(""));
1977
- return container;
1978
- },
1979
-
1980
- // single
1981
- enableInterface: function() {
1982
- if (this.parent.enableInterface.apply(this, arguments)) {
1983
- this.focusser.prop("disabled", !this.isInterfaceEnabled());
1984
- }
1985
- },
1986
-
1987
- // single
1988
- opening: function () {
1989
- var el, range, len;
1990
-
1991
- if (this.opts.minimumResultsForSearch >= 0) {
1992
- this.showSearch(true);
1993
- }
1994
-
1995
- this.parent.opening.apply(this, arguments);
1996
-
1997
- if (this.showSearchInput !== false) {
1998
- // IE appends focusser.val() at the end of field :/ so we manually insert it at the beginning using a range
1999
- // all other browsers handle this just fine
2000
-
2001
- this.search.val(this.focusser.val());
2002
- }
2003
- if (this.opts.shouldFocusInput(this)) {
2004
- this.search.focus();
2005
- // move the cursor to the end after focussing, otherwise it will be at the beginning and
2006
- // new text will appear *before* focusser.val()
2007
- el = this.search.get(0);
2008
- if (el.createTextRange) {
2009
- range = el.createTextRange();
2010
- range.collapse(false);
2011
- range.select();
2012
- } else if (el.setSelectionRange) {
2013
- len = this.search.val().length;
2014
- el.setSelectionRange(len, len);
2015
- }
2016
- }
2017
-
2018
- // initializes search's value with nextSearchTerm (if defined by user)
2019
- // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter
2020
- if(this.search.val() === "") {
2021
- if(this.nextSearchTerm != undefined){
2022
- this.search.val(this.nextSearchTerm);
2023
- this.search.select();
2024
- }
2025
- }
2026
-
2027
- this.focusser.prop("disabled", true).val("");
2028
- this.updateResults(true);
2029
- this.opts.element.trigger($.Event("select2-open"));
2030
- },
2031
-
2032
- // single
2033
- close: function () {
2034
- if (!this.opened()) return;
2035
- this.parent.close.apply(this, arguments);
2036
-
2037
- this.focusser.prop("disabled", false);
2038
-
2039
- if (this.opts.shouldFocusInput(this)) {
2040
- this.focusser.focus();
2041
- }
2042
- },
2043
-
2044
- // single
2045
- focus: function () {
2046
- if (this.opened()) {
2047
- this.close();
2048
- } else {
2049
- this.focusser.prop("disabled", false);
2050
- if (this.opts.shouldFocusInput(this)) {
2051
- this.focusser.focus();
2052
- }
2053
- }
2054
- },
2055
-
2056
- // single
2057
- isFocused: function () {
2058
- return this.container.hasClass("select2-container-active");
2059
- },
2060
-
2061
- // single
2062
- cancel: function () {
2063
- this.parent.cancel.apply(this, arguments);
2064
- this.focusser.prop("disabled", false);
2065
-
2066
- if (this.opts.shouldFocusInput(this)) {
2067
- this.focusser.focus();
2068
- }
2069
- },
2070
-
2071
- // single
2072
- destroy: function() {
2073
- $("label[for='" + this.focusser.attr('id') + "']")
2074
- .attr('for', this.opts.element.attr("id"));
2075
- this.parent.destroy.apply(this, arguments);
2076
-
2077
- cleanupJQueryElements.call(this,
2078
- "selection",
2079
- "focusser"
2080
- );
2081
- },
2082
-
2083
- // single
2084
- initContainer: function () {
2085
-
2086
- var selection,
2087
- container = this.container,
2088
- dropdown = this.dropdown,
2089
- idSuffix = nextUid(),
2090
- elementLabel;
2091
-
2092
- if (this.opts.minimumResultsForSearch < 0) {
2093
- this.showSearch(false);
2094
- } else {
2095
- this.showSearch(true);
2096
- }
2097
-
2098
- this.selection = selection = container.find(".select2-choice");
2099
-
2100
- this.focusser = container.find(".select2-focusser");
2101
-
2102
- // add aria associations
2103
- selection.find(".select2-chosen").attr("id", "select2-chosen-"+idSuffix);
2104
- this.focusser.attr("aria-labelledby", "select2-chosen-"+idSuffix);
2105
- this.results.attr("id", "select2-results-"+idSuffix);
2106
- this.search.attr("aria-owns", "select2-results-"+idSuffix);
2107
-
2108
- // rewrite labels from original element to focusser
2109
- this.focusser.attr("id", "s2id_autogen"+idSuffix);
2110
-
2111
- elementLabel = $("label[for='" + this.opts.element.attr("id") + "']");
2112
- this.opts.element.focus(this.bind(function () { this.focus(); }));
2113
-
2114
- this.focusser.prev()
2115
- .text(elementLabel.text())
2116
- .attr('for', this.focusser.attr('id'));
2117
-
2118
- // Ensure the original element retains an accessible name
2119
- var originalTitle = this.opts.element.attr("title");
2120
- this.opts.element.attr("title", (originalTitle || elementLabel.text()));
2121
-
2122
- this.focusser.attr("tabindex", this.elementTabIndex);
2123
-
2124
- // write label for search field using the label from the focusser element
2125
- this.search.attr("id", this.focusser.attr('id') + '_search');
2126
-
2127
- this.search.prev()
2128
- .text($("label[for='" + this.focusser.attr('id') + "']").text())
2129
- .attr('for', this.search.attr('id'));
2130
-
2131
- this.search.on("keydown", this.bind(function (e) {
2132
- if (!this.isInterfaceEnabled()) return;
2133
-
2134
- // filter 229 keyCodes (input method editor is processing key input)
2135
- if (229 == e.keyCode) return;
2136
-
2137
- if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) {
2138
- // prevent the page from scrolling
2139
- killEvent(e);
2140
- return;
2141
- }
2142
-
2143
- switch (e.which) {
2144
- case KEY.UP:
2145
- case KEY.DOWN:
2146
- this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
2147
- killEvent(e);
2148
- return;
2149
- case KEY.ENTER:
2150
- this.selectHighlighted();
2151
- killEvent(e);
2152
- return;
2153
- case KEY.TAB:
2154
- this.selectHighlighted({noFocus: true});
2155
- return;
2156
- case KEY.ESC:
2157
- this.cancel(e);
2158
- killEvent(e);
2159
- return;
2160
- }
2161
- }));
2162
-
2163
- this.search.on("blur", this.bind(function(e) {
2164
- // a workaround for chrome to keep the search field focussed when the scroll bar is used to scroll the dropdown.
2165
- // without this the search field loses focus which is annoying
2166
- if (document.activeElement === this.body.get(0)) {
2167
- window.setTimeout(this.bind(function() {
2168
- if (this.opened()) {
2169
- this.search.focus();
2170
- }
2171
- }), 0);
2172
- }
2173
- }));
2174
-
2175
- this.focusser.on("keydown", this.bind(function (e) {
2176
- if (!this.isInterfaceEnabled()) return;
2177
-
2178
- if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) {
2179
- return;
2180
- }
2181
-
2182
- if (this.opts.openOnEnter === false && e.which === KEY.ENTER) {
2183
- killEvent(e);
2184
- return;
2185
- }
2186
-
2187
- if (e.which == KEY.DOWN || e.which == KEY.UP
2188
- || (e.which == KEY.ENTER && this.opts.openOnEnter)) {
2189
-
2190
- if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) return;
2191
-
2192
- this.open();
2193
- killEvent(e);
2194
- return;
2195
- }
2196
-
2197
- if (e.which == KEY.DELETE || e.which == KEY.BACKSPACE) {
2198
- if (this.opts.allowClear) {
2199
- this.clear();
2200
- }
2201
- killEvent(e);
2202
- return;
2203
- }
2204
- }));
2205
-
2206
-
2207
- installKeyUpChangeEvent(this.focusser);
2208
- this.focusser.on("keyup-change input", this.bind(function(e) {
2209
- if (this.opts.minimumResultsForSearch >= 0) {
2210
- e.stopPropagation();
2211
- if (this.opened()) return;
2212
- this.open();
2213
- }
2214
- }));
2215
-
2216
- selection.on("mousedown touchstart", "abbr", this.bind(function (e) {
2217
- if (!this.isInterfaceEnabled()) {
2218
- return;
2219
- }
2220
-
2221
- this.clear();
2222
- killEventImmediately(e);
2223
- this.close();
2224
-
2225
- if (this.selection) {
2226
- this.selection.focus();
2227
- }
2228
- }));
2229
-
2230
- selection.on("mousedown touchstart", this.bind(function (e) {
2231
- // Prevent IE from generating a click event on the body
2232
- reinsertElement(selection);
2233
-
2234
- if (!this.container.hasClass("select2-container-active")) {
2235
- this.opts.element.trigger($.Event("select2-focus"));
2236
- }
2237
-
2238
- if (this.opened()) {
2239
- this.close();
2240
- } else if (this.isInterfaceEnabled()) {
2241
- this.open();
2242
- }
2243
-
2244
- killEvent(e);
2245
- }));
2246
-
2247
- dropdown.on("mousedown touchstart", this.bind(function() {
2248
- if (this.opts.shouldFocusInput(this)) {
2249
- this.search.focus();
2250
- }
2251
- }));
2252
-
2253
- selection.on("focus", this.bind(function(e) {
2254
- killEvent(e);
2255
- }));
2256
-
2257
- this.focusser.on("focus", this.bind(function(){
2258
- if (!this.container.hasClass("select2-container-active")) {
2259
- this.opts.element.trigger($.Event("select2-focus"));
2260
- }
2261
- this.container.addClass("select2-container-active");
2262
- })).on("blur", this.bind(function() {
2263
- if (!this.opened()) {
2264
- this.container.removeClass("select2-container-active");
2265
- this.opts.element.trigger($.Event("select2-blur"));
2266
- }
2267
- }));
2268
- this.search.on("focus", this.bind(function(){
2269
- if (!this.container.hasClass("select2-container-active")) {
2270
- this.opts.element.trigger($.Event("select2-focus"));
2271
- }
2272
- this.container.addClass("select2-container-active");
2273
- }));
2274
-
2275
- this.initContainerWidth();
2276
- this.opts.element.hide();
2277
- this.setPlaceholder();
2278
-
2279
- },
2280
-
2281
- // single
2282
- clear: function(triggerChange) {
2283
- var data=this.selection.data("select2-data");
2284
- if (data) { // guard against queued quick consecutive clicks
2285
- var evt = $.Event("select2-clearing");
2286
- this.opts.element.trigger(evt);
2287
- if (evt.isDefaultPrevented()) {
2288
- return;
2289
- }
2290
- var placeholderOption = this.getPlaceholderOption();
2291
- this.opts.element.val(placeholderOption ? placeholderOption.val() : "");
2292
- this.selection.find(".select2-chosen").empty();
2293
- this.selection.removeData("select2-data");
2294
- this.setPlaceholder();
2295
-
2296
- if (triggerChange !== false){
2297
- this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data });
2298
- this.triggerChange({removed:data});
2299
- }
2300
- }
2301
- },
2302
-
2303
- /**
2304
- * Sets selection based on source element's value
2305
- */
2306
- // single
2307
- initSelection: function () {
2308
- var selected;
2309
- if (this.isPlaceholderOptionSelected()) {
2310
- this.updateSelection(null);
2311
- this.close();
2312
- this.setPlaceholder();
2313
- } else {
2314
- var self = this;
2315
- this.opts.initSelection.call(null, this.opts.element, function(selected){
2316
- if (selected !== undefined && selected !== null) {
2317
- self.updateSelection(selected);
2318
- self.close();
2319
- self.setPlaceholder();
2320
- self.nextSearchTerm = self.opts.nextSearchTerm(selected, self.search.val());
2321
- }
2322
- });
2323
- }
2324
- },
2325
-
2326
- isPlaceholderOptionSelected: function() {
2327
- var placeholderOption;
2328
- if (this.getPlaceholder() === undefined) return false; // no placeholder specified so no option should be considered
2329
- return ((placeholderOption = this.getPlaceholderOption()) !== undefined && placeholderOption.prop("selected"))
2330
- || (this.opts.element.val() === "")
2331
- || (this.opts.element.val() === undefined)
2332
- || (this.opts.element.val() === null);
2333
- },
2334
-
2335
- // single
2336
- prepareOpts: function () {
2337
- var opts = this.parent.prepareOpts.apply(this, arguments),
2338
- self=this;
2339
-
2340
- if (opts.element.get(0).tagName.toLowerCase() === "select") {
2341
- // install the selection initializer
2342
- opts.initSelection = function (element, callback) {
2343
- var selected = element.find("option").filter(function() { return this.selected && !this.disabled });
2344
- // a single select box always has a value, no need to null check 'selected'
2345
- callback(self.optionToData(selected));
2346
- };
2347
- } else if ("data" in opts) {
2348
- // install default initSelection when applied to hidden input and data is local
2349
- opts.initSelection = opts.initSelection || function (element, callback) {
2350
- var id = element.val();
2351
- //search in data by id, storing the actual matching item
2352
- var match = null;
2353
- opts.query({
2354
- matcher: function(term, text, el){
2355
- var is_match = equal(id, opts.id(el));
2356
- if (is_match) {
2357
- match = el;
2358
- }
2359
- return is_match;
2360
- },
2361
- callback: !$.isFunction(callback) ? $.noop : function() {
2362
- callback(match);
2363
- }
2364
- });
2365
- };
2366
- }
2367
-
2368
- return opts;
2369
- },
2370
-
2371
- // single
2372
- getPlaceholder: function() {
2373
- // if a placeholder is specified on a single select without a valid placeholder option ignore it
2374
- if (this.select) {
2375
- if (this.getPlaceholderOption() === undefined) {
2376
- return undefined;
2377
- }
2378
- }
2379
-
2380
- return this.parent.getPlaceholder.apply(this, arguments);
2381
- },
2382
-
2383
- // single
2384
- setPlaceholder: function () {
2385
- var placeholder = this.getPlaceholder();
2386
-
2387
- if (this.isPlaceholderOptionSelected() && placeholder !== undefined) {
2388
-
2389
- // check for a placeholder option if attached to a select
2390
- if (this.select && this.getPlaceholderOption() === undefined) return;
2391
-
2392
- this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(placeholder));
2393
-
2394
- this.selection.addClass("select2-default");
2395
-
2396
- this.container.removeClass("select2-allowclear");
2397
- }
2398
- },
2399
-
2400
- // single
2401
- postprocessResults: function (data, initial, noHighlightUpdate) {
2402
- var selected = 0, self = this, showSearchInput = true;
2403
-
2404
- // find the selected element in the result list
2405
-
2406
- this.findHighlightableChoices().each2(function (i, elm) {
2407
- if (equal(self.id(elm.data("select2-data")), self.opts.element.val())) {
2408
- selected = i;
2409
- return false;
2410
- }
2411
- });
2412
-
2413
- // and highlight it
2414
- if (noHighlightUpdate !== false) {
2415
- if (initial === true && selected >= 0) {
2416
- this.highlight(selected);
2417
- } else {
2418
- this.highlight(0);
2419
- }
2420
- }
2421
-
2422
- // hide the search box if this is the first we got the results and there are enough of them for search
2423
-
2424
- if (initial === true) {
2425
- var min = this.opts.minimumResultsForSearch;
2426
- if (min >= 0) {
2427
- this.showSearch(countResults(data.results) >= min);
2428
- }
2429
- }
2430
- },
2431
-
2432
- // single
2433
- showSearch: function(showSearchInput) {
2434
- if (this.showSearchInput === showSearchInput) return;
2435
-
2436
- this.showSearchInput = showSearchInput;
2437
-
2438
- this.dropdown.find(".select2-search").toggleClass("select2-search-hidden", !showSearchInput);
2439
- this.dropdown.find(".select2-search").toggleClass("select2-offscreen", !showSearchInput);
2440
- //add "select2-with-searchbox" to the container if search box is shown
2441
- $(this.dropdown, this.container).toggleClass("select2-with-searchbox", showSearchInput);
2442
- },
2443
-
2444
- // single
2445
- onSelect: function (data, options) {
2446
-
2447
- if (!this.triggerSelect(data)) { return; }
2448
-
2449
- var old = this.opts.element.val(),
2450
- oldData = this.data();
2451
-
2452
- this.opts.element.val(this.id(data));
2453
- this.updateSelection(data);
2454
-
2455
- this.opts.element.trigger({ type: "select2-selected", val: this.id(data), choice: data });
2456
-
2457
- this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val());
2458
- this.close();
2459
-
2460
- if ((!options || !options.noFocus) && this.opts.shouldFocusInput(this)) {
2461
- this.focusser.focus();
2462
- }
2463
-
2464
- if (!equal(old, this.id(data))) {
2465
- this.triggerChange({ added: data, removed: oldData });
2466
- }
2467
- },
2468
-
2469
- // single
2470
- updateSelection: function (data) {
2471
-
2472
- var container=this.selection.find(".select2-chosen"), formatted, cssClass;
2473
-
2474
- this.selection.data("select2-data", data);
2475
-
2476
- container.empty();
2477
- if (data !== null) {
2478
- formatted=this.opts.formatSelection(data, container, this.opts.escapeMarkup);
2479
- }
2480
- if (formatted !== undefined) {
2481
- container.append(formatted);
2482
- }
2483
- cssClass=this.opts.formatSelectionCssClass(data, container);
2484
- if (cssClass !== undefined) {
2485
- container.addClass(cssClass);
2486
- }
2487
-
2488
- this.selection.removeClass("select2-default");
2489
-
2490
- if (this.opts.allowClear && this.getPlaceholder() !== undefined) {
2491
- this.container.addClass("select2-allowclear");
2492
- }
2493
- },
2494
-
2495
- // single
2496
- val: function () {
2497
- var val,
2498
- triggerChange = false,
2499
- data = null,
2500
- self = this,
2501
- oldData = this.data();
2502
-
2503
- if (arguments.length === 0) {
2504
- return this.opts.element.val();
2505
- }
2506
-
2507
- val = arguments[0];
2508
-
2509
- if (arguments.length > 1) {
2510
- triggerChange = arguments[1];
2511
- }
2512
-
2513
- if (this.select) {
2514
- this.select
2515
- .val(val)
2516
- .find("option").filter(function() { return this.selected }).each2(function (i, elm) {
2517
- data = self.optionToData(elm);
2518
- return false;
2519
- });
2520
- this.updateSelection(data);
2521
- this.setPlaceholder();
2522
- if (triggerChange) {
2523
- this.triggerChange({added: data, removed:oldData});
2524
- }
2525
- } else {
2526
- // val is an id. !val is true for [undefined,null,'',0] - 0 is legal
2527
- if (!val && val !== 0) {
2528
- this.clear(triggerChange);
2529
- return;
2530
- }
2531
- if (this.opts.initSelection === undefined) {
2532
- throw new Error("cannot call val() if initSelection() is not defined");
2533
- }
2534
- this.opts.element.val(val);
2535
- this.opts.initSelection(this.opts.element, function(data){
2536
- self.opts.element.val(!data ? "" : self.id(data));
2537
- self.updateSelection(data);
2538
- self.setPlaceholder();
2539
- if (triggerChange) {
2540
- self.triggerChange({added: data, removed:oldData});
2541
- }
2542
- });
2543
- }
2544
- },
2545
-
2546
- // single
2547
- clearSearch: function () {
2548
- this.search.val("");
2549
- this.focusser.val("");
2550
- },
2551
-
2552
- // single
2553
- data: function(value) {
2554
- var data,
2555
- triggerChange = false;
2556
-
2557
- if (arguments.length === 0) {
2558
- data = this.selection.data("select2-data");
2559
- if (data == undefined) data = null;
2560
- return data;
2561
- } else {
2562
- if (arguments.length > 1) {
2563
- triggerChange = arguments[1];
2564
- }
2565
- if (!value) {
2566
- this.clear(triggerChange);
2567
- } else {
2568
- data = this.data();
2569
- this.opts.element.val(!value ? "" : this.id(value));
2570
- this.updateSelection(value);
2571
- if (triggerChange) {
2572
- this.triggerChange({added: value, removed:data});
2573
- }
2574
- }
2575
- }
2576
- }
2577
- });
2578
-
2579
- MultiSelect2 = clazz(AbstractSelect2, {
2580
-
2581
- // multi
2582
- createContainer: function () {
2583
- var container = $(document.createElement("div")).attr({
2584
- "class": "select2-container select2-container-multi"
2585
- }).html([
2586
- "<ul class='select2-choices'>",
2587
- " <li class='select2-search-field'>",
2588
- " <label for='' class='select2-offscreen'></label>",
2589
- " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>",
2590
- " </li>",
2591
- "</ul>",
2592
- "<div class='select2-drop select2-drop-multi select2-display-none'>",
2593
- " <ul class='select2-results'>",
2594
- " </ul>",
2595
- "</div>"].join(""));
2596
- return container;
2597
- },
2598
-
2599
- // multi
2600
- prepareOpts: function () {
2601
- var opts = this.parent.prepareOpts.apply(this, arguments),
2602
- self=this;
2603
-
2604
- // TODO validate placeholder is a string if specified
2605
- if (opts.element.get(0).tagName.toLowerCase() === "select") {
2606
- // install the selection initializer
2607
- opts.initSelection = function (element, callback) {
2608
-
2609
- var data = [];
2610
-
2611
- element.find("option").filter(function() { return this.selected && !this.disabled }).each2(function (i, elm) {
2612
- data.push(self.optionToData(elm));
2613
- });
2614
- callback(data);
2615
- };
2616
- } else if ("data" in opts) {
2617
- // install default initSelection when applied to hidden input and data is local
2618
- opts.initSelection = opts.initSelection || function (element, callback) {
2619
- var ids = splitVal(element.val(), opts.separator, opts.transformVal);
2620
- //search in data by array of ids, storing matching items in a list
2621
- var matches = [];
2622
- opts.query({
2623
- matcher: function(term, text, el){
2624
- var is_match = $.grep(ids, function(id) {
2625
- return equal(id, opts.id(el));
2626
- }).length;
2627
- if (is_match) {
2628
- matches.push(el);
2629
- }
2630
- return is_match;
2631
- },
2632
- callback: !$.isFunction(callback) ? $.noop : function() {
2633
- // reorder matches based on the order they appear in the ids array because right now
2634
- // they are in the order in which they appear in data array
2635
- var ordered = [];
2636
- for (var i = 0; i < ids.length; i++) {
2637
- var id = ids[i];
2638
- for (var j = 0; j < matches.length; j++) {
2639
- var match = matches[j];
2640
- if (equal(id, opts.id(match))) {
2641
- ordered.push(match);
2642
- matches.splice(j, 1);
2643
- break;
2644
- }
2645
- }
2646
- }
2647
- callback(ordered);
2648
- }
2649
- });
2650
- };
2651
- }
2652
-
2653
- return opts;
2654
- },
2655
-
2656
- // multi
2657
- selectChoice: function (choice) {
2658
-
2659
- var selected = this.container.find(".select2-search-choice-focus");
2660
- if (selected.length && choice && choice[0] == selected[0]) {
2661
-
2662
- } else {
2663
- if (selected.length) {
2664
- this.opts.element.trigger("choice-deselected", selected);
2665
- }
2666
- selected.removeClass("select2-search-choice-focus");
2667
- if (choice && choice.length) {
2668
- this.close();
2669
- choice.addClass("select2-search-choice-focus");
2670
- this.opts.element.trigger("choice-selected", choice);
2671
- }
2672
- }
2673
- },
2674
-
2675
- // multi
2676
- destroy: function() {
2677
- $("label[for='" + this.search.attr('id') + "']")
2678
- .attr('for', this.opts.element.attr("id"));
2679
- this.parent.destroy.apply(this, arguments);
2680
-
2681
- cleanupJQueryElements.call(this,
2682
- "searchContainer",
2683
- "selection"
2684
- );
2685
- },
2686
-
2687
- // multi
2688
- initContainer: function () {
2689
-
2690
- var selector = ".select2-choices", selection;
2691
-
2692
- this.searchContainer = this.container.find(".select2-search-field");
2693
- this.selection = selection = this.container.find(selector);
2694
-
2695
- var _this = this;
2696
- this.selection.on("click", ".select2-container:not(.select2-container-disabled) .select2-search-choice:not(.select2-locked)", function (e) {
2697
- _this.search[0].focus();
2698
- _this.selectChoice($(this));
2699
- });
2700
-
2701
- // rewrite labels from original element to focusser
2702
- this.search.attr("id", "s2id_autogen"+nextUid());
2703
-
2704
- this.search.prev()
2705
- .text($("label[for='" + this.opts.element.attr("id") + "']").text())
2706
- .attr('for', this.search.attr('id'));
2707
- this.opts.element.focus(this.bind(function () { this.focus(); }));
2708
-
2709
- this.search.on("input paste", this.bind(function() {
2710
- if (this.search.attr('placeholder') && this.search.val().length == 0) return;
2711
- if (!this.isInterfaceEnabled()) return;
2712
- if (!this.opened()) {
2713
- this.open();
2714
- }
2715
- }));
2716
-
2717
- this.search.attr("tabindex", this.elementTabIndex);
2718
-
2719
- this.keydowns = 0;
2720
- this.search.on("keydown", this.bind(function (e) {
2721
- if (!this.isInterfaceEnabled()) return;
2722
-
2723
- ++this.keydowns;
2724
- var selected = selection.find(".select2-search-choice-focus");
2725
- var prev = selected.prev(".select2-search-choice:not(.select2-locked)");
2726
- var next = selected.next(".select2-search-choice:not(.select2-locked)");
2727
- var pos = getCursorInfo(this.search);
2728
-
2729
- if (selected.length &&
2730
- (e.which == KEY.LEFT || e.which == KEY.RIGHT || e.which == KEY.BACKSPACE || e.which == KEY.DELETE || e.which == KEY.ENTER)) {
2731
- var selectedChoice = selected;
2732
- if (e.which == KEY.LEFT && prev.length) {
2733
- selectedChoice = prev;
2734
- }
2735
- else if (e.which == KEY.RIGHT) {
2736
- selectedChoice = next.length ? next : null;
2737
- }
2738
- else if (e.which === KEY.BACKSPACE) {
2739
- if (this.unselect(selected.first())) {
2740
- this.search.width(10);
2741
- selectedChoice = prev.length ? prev : next;
2742
- }
2743
- } else if (e.which == KEY.DELETE) {
2744
- if (this.unselect(selected.first())) {
2745
- this.search.width(10);
2746
- selectedChoice = next.length ? next : null;
2747
- }
2748
- } else if (e.which == KEY.ENTER) {
2749
- selectedChoice = null;
2750
- }
2751
-
2752
- this.selectChoice(selectedChoice);
2753
- killEvent(e);
2754
- if (!selectedChoice || !selectedChoice.length) {
2755
- this.open();
2756
- }
2757
- return;
2758
- } else if (((e.which === KEY.BACKSPACE && this.keydowns == 1)
2759
- || e.which == KEY.LEFT) && (pos.offset == 0 && !pos.length)) {
2760
-
2761
- this.selectChoice(selection.find(".select2-search-choice:not(.select2-locked)").last());
2762
- killEvent(e);
2763
- return;
2764
- } else {
2765
- this.selectChoice(null);
2766
- }
2767
-
2768
- if (this.opened()) {
2769
- switch (e.which) {
2770
- case KEY.UP:
2771
- case KEY.DOWN:
2772
- this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
2773
- killEvent(e);
2774
- return;
2775
- case KEY.ENTER:
2776
- this.selectHighlighted();
2777
- killEvent(e);
2778
- return;
2779
- case KEY.TAB:
2780
- this.selectHighlighted({noFocus:true});
2781
- this.close();
2782
- return;
2783
- case KEY.ESC:
2784
- this.cancel(e);
2785
- killEvent(e);
2786
- return;
2787
- }
2788
- }
2789
-
2790
- if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e)
2791
- || e.which === KEY.BACKSPACE || e.which === KEY.ESC) {
2792
- return;
2793
- }
2794
-
2795
- if (e.which === KEY.ENTER) {
2796
- if (this.opts.openOnEnter === false) {
2797
- return;
2798
- } else if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
2799
- return;
2800
- }
2801
- }
2802
-
2803
- this.open();
2804
-
2805
- if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) {
2806
- // prevent the page from scrolling
2807
- killEvent(e);
2808
- }
2809
-
2810
- if (e.which === KEY.ENTER) {
2811
- // prevent form from being submitted
2812
- killEvent(e);
2813
- }
2814
-
2815
- }));
2816
-
2817
- this.search.on("keyup", this.bind(function (e) {
2818
- this.keydowns = 0;
2819
- this.resizeSearch();
2820
- })
2821
- );
2822
-
2823
- this.search.on("blur", this.bind(function(e) {
2824
- this.container.removeClass("select2-container-active");
2825
- this.search.removeClass("select2-focused");
2826
- this.selectChoice(null);
2827
- if (!this.opened()) this.clearSearch();
2828
- e.stopImmediatePropagation();
2829
- this.opts.element.trigger($.Event("select2-blur"));
2830
- }));
2831
-
2832
- this.container.on("click", selector, this.bind(function (e) {
2833
- if (!this.isInterfaceEnabled()) return;
2834
- if ($(e.target).closest(".select2-search-choice").length > 0) {
2835
- // clicked inside a select2 search choice, do not open
2836
- return;
2837
- }
2838
- this.selectChoice(null);
2839
- this.clearPlaceholder();
2840
- if (!this.container.hasClass("select2-container-active")) {
2841
- this.opts.element.trigger($.Event("select2-focus"));
2842
- }
2843
- this.open();
2844
- this.focusSearch();
2845
- e.preventDefault();
2846
- }));
2847
-
2848
- this.container.on("focus", selector, this.bind(function () {
2849
- if (!this.isInterfaceEnabled()) return;
2850
- if (!this.container.hasClass("select2-container-active")) {
2851
- this.opts.element.trigger($.Event("select2-focus"));
2852
- }
2853
- this.container.addClass("select2-container-active");
2854
- this.dropdown.addClass("select2-drop-active");
2855
- this.clearPlaceholder();
2856
- }));
2857
-
2858
- this.initContainerWidth();
2859
- this.opts.element.hide();
2860
-
2861
- // set the placeholder if necessary
2862
- this.clearSearch();
2863
- },
2864
-
2865
- // multi
2866
- enableInterface: function() {
2867
- if (this.parent.enableInterface.apply(this, arguments)) {
2868
- this.search.prop("disabled", !this.isInterfaceEnabled());
2869
- }
2870
- },
2871
-
2872
- // multi
2873
- initSelection: function () {
2874
- var data;
2875
- if (this.opts.element.val() === "" && this.opts.element.text() === "") {
2876
- this.updateSelection([]);
2877
- this.close();
2878
- // set the placeholder if necessary
2879
- this.clearSearch();
2880
- }
2881
- if (this.select || this.opts.element.val() !== "") {
2882
- var self = this;
2883
- this.opts.initSelection.call(null, this.opts.element, function(data){
2884
- if (data !== undefined && data !== null) {
2885
- self.updateSelection(data);
2886
- self.close();
2887
- // set the placeholder if necessary
2888
- self.clearSearch();
2889
- }
2890
- });
2891
- }
2892
- },
2893
-
2894
- // multi
2895
- clearSearch: function () {
2896
- var placeholder = this.getPlaceholder(),
2897
- maxWidth = this.getMaxSearchWidth();
2898
-
2899
- if (placeholder !== undefined && this.getVal().length === 0 && this.search.hasClass("select2-focused") === false) {
2900
- this.search.val(placeholder).addClass("select2-default");
2901
- // stretch the search box to full width of the container so as much of the placeholder is visible as possible
2902
- // we could call this.resizeSearch(), but we do not because that requires a sizer and we do not want to create one so early because of a firefox bug, see #944
2903
- this.search.width(maxWidth > 0 ? maxWidth : this.container.css("width"));
2904
- } else {
2905
- this.search.val("").width(10);
2906
- }
2907
- },
2908
-
2909
- // multi
2910
- clearPlaceholder: function () {
2911
- if (this.search.hasClass("select2-default")) {
2912
- this.search.val("").removeClass("select2-default");
2913
- }
2914
- },
2915
-
2916
- // multi
2917
- opening: function () {
2918
- this.clearPlaceholder(); // should be done before super so placeholder is not used to search
2919
- this.resizeSearch();
2920
-
2921
- this.parent.opening.apply(this, arguments);
2922
-
2923
- this.focusSearch();
2924
-
2925
- // initializes search's value with nextSearchTerm (if defined by user)
2926
- // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter
2927
- if(this.search.val() === "") {
2928
- if(this.nextSearchTerm != undefined){
2929
- this.search.val(this.nextSearchTerm);
2930
- this.search.select();
2931
- }
2932
- }
2933
-
2934
- this.updateResults(true);
2935
- if (this.opts.shouldFocusInput(this)) {
2936
- this.search.focus();
2937
- }
2938
- this.opts.element.trigger($.Event("select2-open"));
2939
- },
2940
-
2941
- // multi
2942
- close: function () {
2943
- if (!this.opened()) return;
2944
- this.parent.close.apply(this, arguments);
2945
- },
2946
-
2947
- // multi
2948
- focus: function () {
2949
- this.close();
2950
- this.search.focus();
2951
- },
2952
-
2953
- // multi
2954
- isFocused: function () {
2955
- return this.search.hasClass("select2-focused");
2956
- },
2957
-
2958
- // multi
2959
- updateSelection: function (data) {
2960
- var ids = [], filtered = [], self = this;
2961
-
2962
- // filter out duplicates
2963
- $(data).each(function () {
2964
- if (indexOf(self.id(this), ids) < 0) {
2965
- ids.push(self.id(this));
2966
- filtered.push(this);
2967
- }
2968
- });
2969
- data = filtered;
2970
-
2971
- this.selection.find(".select2-search-choice").remove();
2972
- $(data).each(function () {
2973
- self.addSelectedChoice(this);
2974
- });
2975
- self.postprocessResults();
2976
- },
2977
-
2978
- // multi
2979
- tokenize: function() {
2980
- var input = this.search.val();
2981
- input = this.opts.tokenizer.call(this, input, this.data(), this.bind(this.onSelect), this.opts);
2982
- if (input != null && input != undefined) {
2983
- this.search.val(input);
2984
- if (input.length > 0) {
2985
- this.open();
2986
- }
2987
- }
2988
-
2989
- },
2990
-
2991
- // multi
2992
- onSelect: function (data, options) {
2993
-
2994
- if (!this.triggerSelect(data) || data.text === "") { return; }
2995
-
2996
- this.addSelectedChoice(data);
2997
-
2998
- this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data });
2999
-
3000
- // keep track of the search's value before it gets cleared
3001
- this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val());
3002
-
3003
- this.clearSearch();
3004
- this.updateResults();
3005
-
3006
- if (this.select || !this.opts.closeOnSelect) this.postprocessResults(data, false, this.opts.closeOnSelect===true);
3007
-
3008
- if (this.opts.closeOnSelect) {
3009
- this.close();
3010
- this.search.width(10);
3011
- } else {
3012
- if (this.countSelectableResults()>0) {
3013
- this.search.width(10);
3014
- this.resizeSearch();
3015
- if (this.getMaximumSelectionSize() > 0 && this.val().length >= this.getMaximumSelectionSize()) {
3016
- // if we reached max selection size repaint the results so choices
3017
- // are replaced with the max selection reached message
3018
- this.updateResults(true);
3019
- } else {
3020
- // initializes search's value with nextSearchTerm and update search result
3021
- if(this.nextSearchTerm != undefined){
3022
- this.search.val(this.nextSearchTerm);
3023
- this.updateResults();
3024
- this.search.select();
3025
- }
3026
- }
3027
- this.positionDropdown();
3028
- } else {
3029
- // if nothing left to select close
3030
- this.close();
3031
- this.search.width(10);
3032
- }
3033
- }
3034
-
3035
- // since its not possible to select an element that has already been
3036
- // added we do not need to check if this is a new element before firing change
3037
- this.triggerChange({ added: data });
3038
-
3039
- if (!options || !options.noFocus)
3040
- this.focusSearch();
3041
- },
3042
-
3043
- // multi
3044
- cancel: function () {
3045
- this.close();
3046
- this.focusSearch();
3047
- },
3048
-
3049
- addSelectedChoice: function (data) {
3050
- var enableChoice = !data.locked,
3051
- enabledItem = $(
3052
- "<li class='select2-search-choice'>" +
3053
- " <div></div>" +
3054
- " <a href='#' class='select2-search-choice-close' tabindex='-1'></a>" +
3055
- "</li>"),
3056
- disabledItem = $(
3057
- "<li class='select2-search-choice select2-locked'>" +
3058
- "<div></div>" +
3059
- "</li>");
3060
- var choice = enableChoice ? enabledItem : disabledItem,
3061
- id = this.id(data),
3062
- val = this.getVal(),
3063
- formatted,
3064
- cssClass;
3065
-
3066
- formatted=this.opts.formatSelection(data, choice.find("div"), this.opts.escapeMarkup);
3067
- if (formatted != undefined) {
3068
- choice.find("div").replaceWith($("<div></div>").html(formatted));
3069
- }
3070
- cssClass=this.opts.formatSelectionCssClass(data, choice.find("div"));
3071
- if (cssClass != undefined) {
3072
- choice.addClass(cssClass);
3073
- }
3074
-
3075
- if(enableChoice){
3076
- choice.find(".select2-search-choice-close")
3077
- .on("mousedown", killEvent)
3078
- .on("click dblclick", this.bind(function (e) {
3079
- if (!this.isInterfaceEnabled()) return;
3080
-
3081
- this.unselect($(e.target));
3082
- this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
3083
- killEvent(e);
3084
- this.close();
3085
- this.focusSearch();
3086
- })).on("focus", this.bind(function () {
3087
- if (!this.isInterfaceEnabled()) return;
3088
- this.container.addClass("select2-container-active");
3089
- this.dropdown.addClass("select2-drop-active");
3090
- }));
3091
- }
3092
-
3093
- choice.data("select2-data", data);
3094
- choice.insertBefore(this.searchContainer);
3095
-
3096
- val.push(id);
3097
- this.setVal(val);
3098
- },
3099
-
3100
- // multi
3101
- unselect: function (selected) {
3102
- var val = this.getVal(),
3103
- data,
3104
- index;
3105
- selected = selected.closest(".select2-search-choice");
3106
-
3107
- if (selected.length === 0) {
3108
- throw "Invalid argument: " + selected + ". Must be .select2-search-choice";
3109
- }
3110
-
3111
- data = selected.data("select2-data");
3112
-
3113
- if (!data) {
3114
- // prevent a race condition when the 'x' is clicked really fast repeatedly the event can be queued
3115
- // and invoked on an element already removed
3116
- return;
3117
- }
3118
-
3119
- var evt = $.Event("select2-removing");
3120
- evt.val = this.id(data);
3121
- evt.choice = data;
3122
- this.opts.element.trigger(evt);
3123
-
3124
- if (evt.isDefaultPrevented()) {
3125
- return false;
3126
- }
3127
-
3128
- while((index = indexOf(this.id(data), val)) >= 0) {
3129
- val.splice(index, 1);
3130
- this.setVal(val);
3131
- if (this.select) this.postprocessResults();
3132
- }
3133
-
3134
- selected.remove();
3135
-
3136
- this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data });
3137
- this.triggerChange({ removed: data });
3138
-
3139
- return true;
3140
- },
3141
-
3142
- // multi
3143
- postprocessResults: function (data, initial, noHighlightUpdate) {
3144
- var val = this.getVal(),
3145
- choices = this.results.find(".select2-result"),
3146
- compound = this.results.find(".select2-result-with-children"),
3147
- self = this;
3148
-
3149
- choices.each2(function (i, choice) {
3150
- var id = self.id(choice.data("select2-data"));
3151
- if (indexOf(id, val) >= 0) {
3152
- choice.addClass("select2-selected");
3153
- // mark all children of the selected parent as selected
3154
- choice.find(".select2-result-selectable").addClass("select2-selected");
3155
- }
3156
- });
3157
-
3158
- compound.each2(function(i, choice) {
3159
- // hide an optgroup if it doesn't have any selectable children
3160
- if (!choice.is('.select2-result-selectable')
3161
- && choice.find(".select2-result-selectable:not(.select2-selected)").length === 0) {
3162
- choice.addClass("select2-selected");
3163
- }
3164
- });
3165
-
3166
- if (this.highlight() == -1 && noHighlightUpdate !== false && this.opts.closeOnSelect === true){
3167
- self.highlight(0);
3168
- }
3169
-
3170
- //If all results are chosen render formatNoMatches
3171
- if(!this.opts.createSearchChoice && !choices.filter('.select2-result:not(.select2-selected)').length > 0){
3172
- if(!data || data && !data.more && this.results.find(".select2-no-results").length === 0) {
3173
- if (checkFormatter(self.opts.formatNoMatches, "formatNoMatches")) {
3174
- this.results.append("<li class='select2-no-results'>" + evaluate(self.opts.formatNoMatches, self.opts.element, self.search.val()) + "</li>");
3175
- }
3176
- }
3177
- }
3178
-
3179
- },
3180
-
3181
- // multi
3182
- getMaxSearchWidth: function() {
3183
- return this.selection.width() - getSideBorderPadding(this.search);
3184
- },
3185
-
3186
- // multi
3187
- resizeSearch: function () {
3188
- var minimumWidth, left, maxWidth, containerLeft, searchWidth,
3189
- sideBorderPadding = getSideBorderPadding(this.search);
3190
-
3191
- minimumWidth = measureTextWidth(this.search) + 10;
3192
-
3193
- left = this.search.offset().left;
3194
-
3195
- maxWidth = this.selection.width();
3196
- containerLeft = this.selection.offset().left;
3197
-
3198
- searchWidth = maxWidth - (left - containerLeft) - sideBorderPadding;
3199
-
3200
- if (searchWidth < minimumWidth) {
3201
- searchWidth = maxWidth - sideBorderPadding;
3202
- }
3203
-
3204
- if (searchWidth < 40) {
3205
- searchWidth = maxWidth - sideBorderPadding;
3206
- }
3207
-
3208
- if (searchWidth <= 0) {
3209
- searchWidth = minimumWidth;
3210
- }
3211
-
3212
- this.search.width(Math.floor(searchWidth));
3213
- },
3214
-
3215
- // multi
3216
- getVal: function () {
3217
- var val;
3218
- if (this.select) {
3219
- val = this.select.val();
3220
- return val === null ? [] : val;
3221
- } else {
3222
- val = this.opts.element.val();
3223
- return splitVal(val, this.opts.separator, this.opts.transformVal);
3224
- }
3225
- },
3226
-
3227
- // multi
3228
- setVal: function (val) {
3229
- var unique;
3230
- if (this.select) {
3231
- this.select.val(val);
3232
- } else {
3233
- unique = [];
3234
- // filter out duplicates
3235
- $(val).each(function () {
3236
- if (indexOf(this, unique) < 0) unique.push(this);
3237
- });
3238
- this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator));
3239
- }
3240
- },
3241
-
3242
- // multi
3243
- buildChangeDetails: function (old, current) {
3244
- var current = current.slice(0),
3245
- old = old.slice(0);
3246
-
3247
- // remove intersection from each array
3248
- for (var i = 0; i < current.length; i++) {
3249
- for (var j = 0; j < old.length; j++) {
3250
- if (equal(this.opts.id(current[i]), this.opts.id(old[j]))) {
3251
- current.splice(i, 1);
3252
- if(i>0){
3253
- i--;
3254
- }
3255
- old.splice(j, 1);
3256
- j--;
3257
- }
3258
- }
3259
- }
3260
-
3261
- return {added: current, removed: old};
3262
- },
3263
-
3264
-
3265
- // multi
3266
- val: function (val, triggerChange) {
3267
- var oldData, self=this;
3268
-
3269
- if (arguments.length === 0) {
3270
- return this.getVal();
3271
- }
3272
-
3273
- oldData=this.data();
3274
- if (!oldData.length) oldData=[];
3275
-
3276
- // val is an id. !val is true for [undefined,null,'',0] - 0 is legal
3277
- if (!val && val !== 0) {
3278
- this.opts.element.val("");
3279
- this.updateSelection([]);
3280
- this.clearSearch();
3281
- if (triggerChange) {
3282
- this.triggerChange({added: this.data(), removed: oldData});
3283
- }
3284
- return;
3285
- }
3286
-
3287
- // val is a list of ids
3288
- this.setVal(val);
3289
-
3290
- if (this.select) {
3291
- this.opts.initSelection(this.select, this.bind(this.updateSelection));
3292
- if (triggerChange) {
3293
- this.triggerChange(this.buildChangeDetails(oldData, this.data()));
3294
- }
3295
- } else {
3296
- if (this.opts.initSelection === undefined) {
3297
- throw new Error("val() cannot be called if initSelection() is not defined");
3298
- }
3299
-
3300
- this.opts.initSelection(this.opts.element, function(data){
3301
- var ids=$.map(data, self.id);
3302
- self.setVal(ids);
3303
- self.updateSelection(data);
3304
- self.clearSearch();
3305
- if (triggerChange) {
3306
- self.triggerChange(self.buildChangeDetails(oldData, self.data()));
3307
- }
3308
- });
3309
- }
3310
- this.clearSearch();
3311
- },
3312
-
3313
- // multi
3314
- onSortStart: function() {
3315
- if (this.select) {
3316
- throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead.");
3317
- }
3318
-
3319
- // collapse search field into 0 width so its container can be collapsed as well
3320
- this.search.width(0);
3321
- // hide the container
3322
- this.searchContainer.hide();
3323
- },
3324
-
3325
- // multi
3326
- onSortEnd:function() {
3327
-
3328
- var val=[], self=this;
3329
-
3330
- // show search and move it to the end of the list
3331
- this.searchContainer.show();
3332
- // make sure the search container is the last item in the list
3333
- this.searchContainer.appendTo(this.searchContainer.parent());
3334
- // since we collapsed the width in dragStarted, we resize it here
3335
- this.resizeSearch();
3336
-
3337
- // update selection
3338
- this.selection.find(".select2-search-choice").each(function() {
3339
- val.push(self.opts.id($(this).data("select2-data")));
3340
- });
3341
- this.setVal(val);
3342
- this.triggerChange();
3343
- },
3344
-
3345
- // multi
3346
- data: function(values, triggerChange) {
3347
- var self=this, ids, old;
3348
- if (arguments.length === 0) {
3349
- return this.selection
3350
- .children(".select2-search-choice")
3351
- .map(function() { return $(this).data("select2-data"); })
3352
- .get();
3353
- } else {
3354
- old = this.data();
3355
- if (!values) { values = []; }
3356
- ids = $.map(values, function(e) { return self.opts.id(e); });
3357
- this.setVal(ids);
3358
- this.updateSelection(values);
3359
- this.clearSearch();
3360
- if (triggerChange) {
3361
- this.triggerChange(this.buildChangeDetails(old, this.data()));
3362
- }
3363
- }
3364
- }
3365
- });
3366
-
3367
- $.fn.select2 = function () {
3368
-
3369
- var args = Array.prototype.slice.call(arguments, 0),
3370
- opts,
3371
- select2,
3372
- method, value, multiple,
3373
- allowedMethods = ["val", "destroy", "opened", "open", "close", "focus", "isFocused", "container", "dropdown", "onSortStart", "onSortEnd", "enable", "disable", "readonly", "positionDropdown", "data", "search"],
3374
- valueMethods = ["opened", "isFocused", "container", "dropdown"],
3375
- propertyMethods = ["val", "data"],
3376
- methodsMap = { search: "externalSearch" };
3377
-
3378
- this.each(function () {
3379
- if (args.length === 0 || typeof(args[0]) === "object") {
3380
- opts = args.length === 0 ? {} : $.extend({}, args[0]);
3381
- opts.element = $(this);
3382
-
3383
- if (opts.element.get(0).tagName.toLowerCase() === "select") {
3384
- multiple = opts.element.prop("multiple");
3385
- } else {
3386
- multiple = opts.multiple || false;
3387
- if ("tags" in opts) {opts.multiple = multiple = true;}
3388
- }
3389
-
3390
- select2 = multiple ? new window.Select2["class"].multi() : new window.Select2["class"].single();
3391
- select2.init(opts);
3392
- } else if (typeof(args[0]) === "string") {
3393
-
3394
- if (indexOf(args[0], allowedMethods) < 0) {
3395
- throw "Unknown method: " + args[0];
3396
- }
3397
-
3398
- value = undefined;
3399
- select2 = $(this).data("select2");
3400
- if (select2 === undefined) return;
3401
-
3402
- method=args[0];
3403
-
3404
- if (method === "container") {
3405
- value = select2.container;
3406
- } else if (method === "dropdown") {
3407
- value = select2.dropdown;
3408
- } else {
3409
- if (methodsMap[method]) method = methodsMap[method];
3410
-
3411
- value = select2[method].apply(select2, args.slice(1));
3412
- }
3413
- if (indexOf(args[0], valueMethods) >= 0
3414
- || (indexOf(args[0], propertyMethods) >= 0 && args.length == 1)) {
3415
- return false; // abort the iteration, ready to return first matched value
3416
- }
3417
- } else {
3418
- throw "Invalid arguments to select2 plugin: " + args;
3419
- }
3420
- });
3421
- return (value === undefined) ? this : value;
3422
- };
3423
-
3424
- // plugin defaults, accessible to users
3425
- $.fn.select2.defaults = {
3426
- width: "copy",
3427
- loadMorePadding: 0,
3428
- closeOnSelect: true,
3429
- openOnEnter: true,
3430
- containerCss: {},
3431
- dropdownCss: {},
3432
- containerCssClass: "",
3433
- dropdownCssClass: "",
3434
- formatResult: function(result, container, query, escapeMarkup) {
3435
- var markup=[];
3436
- markMatch(this.text(result), query.term, markup, escapeMarkup);
3437
- return markup.join("");
3438
- },
3439
- transformVal: function(val) {
3440
- return $.trim(val);
3441
- },
3442
- formatSelection: function (data, container, escapeMarkup) {
3443
- return data ? escapeMarkup(this.text(data)) : undefined;
3444
- },
3445
- sortResults: function (results, container, query) {
3446
- return results;
3447
- },
3448
- formatResultCssClass: function(data) {return data.css;},
3449
- formatSelectionCssClass: function(data, container) {return undefined;},
3450
- minimumResultsForSearch: 0,
3451
- minimumInputLength: 0,
3452
- maximumInputLength: null,
3453
- maximumSelectionSize: 0,
3454
- id: function (e) { return e == undefined ? null : e.id; },
3455
- text: function (e) {
3456
- if (e && this.data && this.data.text) {
3457
- if ($.isFunction(this.data.text)) {
3458
- return this.data.text(e);
3459
- } else {
3460
- return e[this.data.text];
3461
- }
3462
- } else {
3463
- return e.text;
3464
- }
3465
- },
3466
- matcher: function(term, text) {
3467
- return stripDiacritics(''+text).toUpperCase().indexOf(stripDiacritics(''+term).toUpperCase()) >= 0;
3468
- },
3469
- separator: ",",
3470
- tokenSeparators: [],
3471
- tokenizer: defaultTokenizer,
3472
- escapeMarkup: defaultEscapeMarkup,
3473
- blurOnChange: false,
3474
- selectOnBlur: false,
3475
- adaptContainerCssClass: function(c) { return c; },
3476
- adaptDropdownCssClass: function(c) { return null; },
3477
- nextSearchTerm: function(selectedObject, currentSearchTerm) { return undefined; },
3478
- searchInputPlaceholder: '',
3479
- createSearchChoicePosition: 'top',
3480
- shouldFocusInput: function (instance) {
3481
- // Attempt to detect touch devices
3482
- var supportsTouchEvents = (('ontouchstart' in window) ||
3483
- (navigator.msMaxTouchPoints > 0));
3484
-
3485
- // Only devices which support touch events should be special cased
3486
- if (!supportsTouchEvents) {
3487
- return true;
3488
- }
3489
-
3490
- // Never focus the input if search is disabled
3491
- if (instance.opts.minimumResultsForSearch < 0) {
3492
- return false;
3493
- }
3494
-
3495
- return true;
3496
- }
3497
- };
3498
-
3499
- $.fn.select2.locales = [];
3500
-
3501
- $.fn.select2.locales['en'] = {
3502
- formatMatches: function (matches) { if (matches === 1) { return "One result is available, press enter to select it."; } return matches + " results are available, use up and down arrow keys to navigate."; },
3503
- formatNoMatches: function () { return "No matches found"; },
3504
- formatAjaxError: function (jqXHR, textStatus, errorThrown) { return "Loading failed"; },
3505
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " or more character" + (n == 1 ? "" : "s"); },
3506
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Please delete " + n + " character" + (n == 1 ? "" : "s"); },
3507
- formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); },
3508
- formatLoadMore: function (pageNumber) { return "Loading more results…"; },
3509
- formatSearching: function () { return "Searching…"; }
3510
- };
3511
-
3512
- $.extend($.fn.select2.defaults, $.fn.select2.locales['en']);
3513
-
3514
- $.fn.select2.ajaxDefaults = {
3515
- transport: $.ajax,
3516
- params: {
3517
- type: "GET",
3518
- cache: false,
3519
- dataType: "json"
3520
- }
3521
- };
3522
-
3523
- // exports
3524
- window.Select2 = {
3525
- query: {
3526
- ajax: ajax,
3527
- local: local,
3528
- tags: tags
3529
- }, util: {
3530
- debounce: debounce,
3531
- markMatch: markMatch,
3532
- escapeMarkup: defaultEscapeMarkup,
3533
- stripDiacritics: stripDiacritics
3534
- }, "class": {
3535
- "abstract": AbstractSelect2,
3536
- "single": SingleSelect2,
3537
- "multi": MultiSelect2
3538
- }
3539
- };
3540
-
3541
- }(jQuery));
1
+ /*
2
+ Copyright 2012 Igor Vaynberg
3
+
4
+ Version: 3.5.2 Timestamp: Sat Nov 1 14:43:36 EDT 2014
5
+
6
+ This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
7
+ General Public License version 2 (the "GPL License"). You may choose either license to govern your
8
+ use of this software only upon the condition that you accept all of the terms of either the Apache
9
+ License or the GPL License.
10
+
11
+ You may obtain a copy of the Apache License and the GPL License at:
12
+
13
+ http://www.apache.org/licenses/LICENSE-2.0
14
+ http://www.gnu.org/licenses/gpl-2.0.html
15
+
16
+ Unless required by applicable law or agreed to in writing, software distributed under the
17
+ Apache License or the GPL License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
18
+ CONDITIONS OF ANY KIND, either express or implied. See the Apache License and the GPL License for
19
+ the specific language governing permissions and limitations under the Apache License and the GPL License.
20
+ */
21
+ (function ($) {
22
+ if(typeof $.fn.each2 == "undefined") {
23
+ $.extend($.fn, {
24
+ /*
25
+ * 4-10 times faster .each replacement
26
+ * use it carefully, as it overrides jQuery context of element on each iteration
27
+ */
28
+ each2 : function (c) {
29
+ var j = $([0]), i = -1, l = this.length;
30
+ while (
31
+ ++i < l
32
+ && (j.context = j[0] = this[i])
33
+ && c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object
34
+ );
35
+ return this;
36
+ }
37
+ });
38
+ }
39
+ })(jQuery);
40
+
41
+ (function ($, undefined) {
42
+ "use strict";
43
+ /*global document, window, jQuery, console */
44
+
45
+ if (window.Select2 !== undefined) {
46
+ return;
47
+ }
48
+
49
+ var AbstractSelect2, SingleSelect2, MultiSelect2, nextUid, sizer,
50
+ lastMousePosition={x:0,y:0}, $document, scrollBarDimensions,
51
+
52
+ KEY = {
53
+ TAB: 9,
54
+ ENTER: 13,
55
+ ESC: 27,
56
+ SPACE: 32,
57
+ LEFT: 37,
58
+ UP: 38,
59
+ RIGHT: 39,
60
+ DOWN: 40,
61
+ SHIFT: 16,
62
+ CTRL: 17,
63
+ ALT: 18,
64
+ PAGE_UP: 33,
65
+ PAGE_DOWN: 34,
66
+ HOME: 36,
67
+ END: 35,
68
+ BACKSPACE: 8,
69
+ DELETE: 46,
70
+ isArrow: function (k) {
71
+ k = k.which ? k.which : k;
72
+ switch (k) {
73
+ case KEY.LEFT:
74
+ case KEY.RIGHT:
75
+ case KEY.UP:
76
+ case KEY.DOWN:
77
+ return true;
78
+ }
79
+ return false;
80
+ },
81
+ isControl: function (e) {
82
+ var k = e.which;
83
+ switch (k) {
84
+ case KEY.SHIFT:
85
+ case KEY.CTRL:
86
+ case KEY.ALT:
87
+ return true;
88
+ }
89
+
90
+ if (e.metaKey) return true;
91
+
92
+ return false;
93
+ },
94
+ isFunctionKey: function (k) {
95
+ k = k.which ? k.which : k;
96
+ return k >= 112 && k <= 123;
97
+ }
98
+ },
99
+ MEASURE_SCROLLBAR_TEMPLATE = "<div class='select2-measure-scrollbar'></div>",
100
+
101
+ DIACRITICS = {"\u24B6":"A","\uFF21":"A","\u00C0":"A","\u00C1":"A","\u00C2":"A","\u1EA6":"A","\u1EA4":"A","\u1EAA":"A","\u1EA8":"A","\u00C3":"A","\u0100":"A","\u0102":"A","\u1EB0":"A","\u1EAE":"A","\u1EB4":"A","\u1EB2":"A","\u0226":"A","\u01E0":"A","\u00C4":"A","\u01DE":"A","\u1EA2":"A","\u00C5":"A","\u01FA":"A","\u01CD":"A","\u0200":"A","\u0202":"A","\u1EA0":"A","\u1EAC":"A","\u1EB6":"A","\u1E00":"A","\u0104":"A","\u023A":"A","\u2C6F":"A","\uA732":"AA","\u00C6":"AE","\u01FC":"AE","\u01E2":"AE","\uA734":"AO","\uA736":"AU","\uA738":"AV","\uA73A":"AV","\uA73C":"AY","\u24B7":"B","\uFF22":"B","\u1E02":"B","\u1E04":"B","\u1E06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24B8":"C","\uFF23":"C","\u0106":"C","\u0108":"C","\u010A":"C","\u010C":"C","\u00C7":"C","\u1E08":"C","\u0187":"C","\u023B":"C","\uA73E":"C","\u24B9":"D","\uFF24":"D","\u1E0A":"D","\u010E":"D","\u1E0C":"D","\u1E10":"D","\u1E12":"D","\u1E0E":"D","\u0110":"D","\u018B":"D","\u018A":"D","\u0189":"D","\uA779":"D","\u01F1":"DZ","\u01C4":"DZ","\u01F2":"Dz","\u01C5":"Dz","\u24BA":"E","\uFF25":"E","\u00C8":"E","\u00C9":"E","\u00CA":"E","\u1EC0":"E","\u1EBE":"E","\u1EC4":"E","\u1EC2":"E","\u1EBC":"E","\u0112":"E","\u1E14":"E","\u1E16":"E","\u0114":"E","\u0116":"E","\u00CB":"E","\u1EBA":"E","\u011A":"E","\u0204":"E","\u0206":"E","\u1EB8":"E","\u1EC6":"E","\u0228":"E","\u1E1C":"E","\u0118":"E","\u1E18":"E","\u1E1A":"E","\u0190":"E","\u018E":"E","\u24BB":"F","\uFF26":"F","\u1E1E":"F","\u0191":"F","\uA77B":"F","\u24BC":"G","\uFF27":"G","\u01F4":"G","\u011C":"G","\u1E20":"G","\u011E":"G","\u0120":"G","\u01E6":"G","\u0122":"G","\u01E4":"G","\u0193":"G","\uA7A0":"G","\uA77D":"G","\uA77E":"G","\u24BD":"H","\uFF28":"H","\u0124":"H","\u1E22":"H","\u1E26":"H","\u021E":"H","\u1E24":"H","\u1E28":"H","\u1E2A":"H","\u0126":"H","\u2C67":"H","\u2C75":"H","\uA78D":"H","\u24BE":"I","\uFF29":"I","\u00CC":"I","\u00CD":"I","\u00CE":"I","\u0128":"I","\u012A":"I","\u012C":"I","\u0130":"I","\u00CF":"I","\u1E2E":"I","\u1EC8":"I","\u01CF":"I","\u0208":"I","\u020A":"I","\u1ECA":"I","\u012E":"I","\u1E2C":"I","\u0197":"I","\u24BF":"J","\uFF2A":"J","\u0134":"J","\u0248":"J","\u24C0":"K","\uFF2B":"K","\u1E30":"K","\u01E8":"K","\u1E32":"K","\u0136":"K","\u1E34":"K","\u0198":"K","\u2C69":"K","\uA740":"K","\uA742":"K","\uA744":"K","\uA7A2":"K","\u24C1":"L","\uFF2C":"L","\u013F":"L","\u0139":"L","\u013D":"L","\u1E36":"L","\u1E38":"L","\u013B":"L","\u1E3C":"L","\u1E3A":"L","\u0141":"L","\u023D":"L","\u2C62":"L","\u2C60":"L","\uA748":"L","\uA746":"L","\uA780":"L","\u01C7":"LJ","\u01C8":"Lj","\u24C2":"M","\uFF2D":"M","\u1E3E":"M","\u1E40":"M","\u1E42":"M","\u2C6E":"M","\u019C":"M","\u24C3":"N","\uFF2E":"N","\u01F8":"N","\u0143":"N","\u00D1":"N","\u1E44":"N","\u0147":"N","\u1E46":"N","\u0145":"N","\u1E4A":"N","\u1E48":"N","\u0220":"N","\u019D":"N","\uA790":"N","\uA7A4":"N","\u01CA":"NJ","\u01CB":"Nj","\u24C4":"O","\uFF2F":"O","\u00D2":"O","\u00D3":"O","\u00D4":"O","\u1ED2":"O","\u1ED0":"O","\u1ED6":"O","\u1ED4":"O","\u00D5":"O","\u1E4C":"O","\u022C":"O","\u1E4E":"O","\u014C":"O","\u1E50":"O","\u1E52":"O","\u014E":"O","\u022E":"O","\u0230":"O","\u00D6":"O","\u022A":"O","\u1ECE":"O","\u0150":"O","\u01D1":"O","\u020C":"O","\u020E":"O","\u01A0":"O","\u1EDC":"O","\u1EDA":"O","\u1EE0":"O","\u1EDE":"O","\u1EE2":"O","\u1ECC":"O","\u1ED8":"O","\u01EA":"O","\u01EC":"O","\u00D8":"O","\u01FE":"O","\u0186":"O","\u019F":"O","\uA74A":"O","\uA74C":"O","\u01A2":"OI","\uA74E":"OO","\u0222":"OU","\u24C5":"P","\uFF30":"P","\u1E54":"P","\u1E56":"P","\u01A4":"P","\u2C63":"P","\uA750":"P","\uA752":"P","\uA754":"P","\u24C6":"Q","\uFF31":"Q","\uA756":"Q","\uA758":"Q","\u024A":"Q","\u24C7":"R","\uFF32":"R","\u0154":"R","\u1E58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1E5A":"R","\u1E5C":"R","\u0156":"R","\u1E5E":"R","\u024C":"R","\u2C64":"R","\uA75A":"R","\uA7A6":"R","\uA782":"R","\u24C8":"S","\uFF33":"S","\u1E9E":"S","\u015A":"S","\u1E64":"S","\u015C":"S","\u1E60":"S","\u0160":"S","\u1E66":"S","\u1E62":"S","\u1E68":"S","\u0218":"S","\u015E":"S","\u2C7E":"S","\uA7A8":"S","\uA784":"S","\u24C9":"T","\uFF34":"T","\u1E6A":"T","\u0164":"T","\u1E6C":"T","\u021A":"T","\u0162":"T","\u1E70":"T","\u1E6E":"T","\u0166":"T","\u01AC":"T","\u01AE":"T","\u023E":"T","\uA786":"T","\uA728":"TZ","\u24CA":"U","\uFF35":"U","\u00D9":"U","\u00DA":"U","\u00DB":"U","\u0168":"U","\u1E78":"U","\u016A":"U","\u1E7A":"U","\u016C":"U","\u00DC":"U","\u01DB":"U","\u01D7":"U","\u01D5":"U","\u01D9":"U","\u1EE6":"U","\u016E":"U","\u0170":"U","\u01D3":"U","\u0214":"U","\u0216":"U","\u01AF":"U","\u1EEA":"U","\u1EE8":"U","\u1EEE":"U","\u1EEC":"U","\u1EF0":"U","\u1EE4":"U","\u1E72":"U","\u0172":"U","\u1E76":"U","\u1E74":"U","\u0244":"U","\u24CB":"V","\uFF36":"V","\u1E7C":"V","\u1E7E":"V","\u01B2":"V","\uA75E":"V","\u0245":"V","\uA760":"VY","\u24CC":"W","\uFF37":"W","\u1E80":"W","\u1E82":"W","\u0174":"W","\u1E86":"W","\u1E84":"W","\u1E88":"W","\u2C72":"W","\u24CD":"X","\uFF38":"X","\u1E8A":"X","\u1E8C":"X","\u24CE":"Y","\uFF39":"Y","\u1EF2":"Y","\u00DD":"Y","\u0176":"Y","\u1EF8":"Y","\u0232":"Y","\u1E8E":"Y","\u0178":"Y","\u1EF6":"Y","\u1EF4":"Y","\u01B3":"Y","\u024E":"Y","\u1EFE":"Y","\u24CF":"Z","\uFF3A":"Z","\u0179":"Z","\u1E90":"Z","\u017B":"Z","\u017D":"Z","\u1E92":"Z","\u1E94":"Z","\u01B5":"Z","\u0224":"Z","\u2C7F":"Z","\u2C6B":"Z","\uA762":"Z","\u24D0":"a","\uFF41":"a","\u1E9A":"a","\u00E0":"a","\u00E1":"a","\u00E2":"a","\u1EA7":"a","\u1EA5":"a","\u1EAB":"a","\u1EA9":"a","\u00E3":"a","\u0101":"a","\u0103":"a","\u1EB1":"a","\u1EAF":"a","\u1EB5":"a","\u1EB3":"a","\u0227":"a","\u01E1":"a","\u00E4":"a","\u01DF":"a","\u1EA3":"a","\u00E5":"a","\u01FB":"a","\u01CE":"a","\u0201":"a","\u0203":"a","\u1EA1":"a","\u1EAD":"a","\u1EB7":"a","\u1E01":"a","\u0105":"a","\u2C65":"a","\u0250":"a","\uA733":"aa","\u00E6":"ae","\u01FD":"ae","\u01E3":"ae","\uA735":"ao","\uA737":"au","\uA739":"av","\uA73B":"av","\uA73D":"ay","\u24D1":"b","\uFF42":"b","\u1E03":"b","\u1E05":"b","\u1E07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24D2":"c","\uFF43":"c","\u0107":"c","\u0109":"c","\u010B":"c","\u010D":"c","\u00E7":"c","\u1E09":"c","\u0188":"c","\u023C":"c","\uA73F":"c","\u2184":"c","\u24D3":"d","\uFF44":"d","\u1E0B":"d","\u010F":"d","\u1E0D":"d","\u1E11":"d","\u1E13":"d","\u1E0F":"d","\u0111":"d","\u018C":"d","\u0256":"d","\u0257":"d","\uA77A":"d","\u01F3":"dz","\u01C6":"dz","\u24D4":"e","\uFF45":"e","\u00E8":"e","\u00E9":"e","\u00EA":"e","\u1EC1":"e","\u1EBF":"e","\u1EC5":"e","\u1EC3":"e","\u1EBD":"e","\u0113":"e","\u1E15":"e","\u1E17":"e","\u0115":"e","\u0117":"e","\u00EB":"e","\u1EBB":"e","\u011B":"e","\u0205":"e","\u0207":"e","\u1EB9":"e","\u1EC7":"e","\u0229":"e","\u1E1D":"e","\u0119":"e","\u1E19":"e","\u1E1B":"e","\u0247":"e","\u025B":"e","\u01DD":"e","\u24D5":"f","\uFF46":"f","\u1E1F":"f","\u0192":"f","\uA77C":"f","\u24D6":"g","\uFF47":"g","\u01F5":"g","\u011D":"g","\u1E21":"g","\u011F":"g","\u0121":"g","\u01E7":"g","\u0123":"g","\u01E5":"g","\u0260":"g","\uA7A1":"g","\u1D79":"g","\uA77F":"g","\u24D7":"h","\uFF48":"h","\u0125":"h","\u1E23":"h","\u1E27":"h","\u021F":"h","\u1E25":"h","\u1E29":"h","\u1E2B":"h","\u1E96":"h","\u0127":"h","\u2C68":"h","\u2C76":"h","\u0265":"h","\u0195":"hv","\u24D8":"i","\uFF49":"i","\u00EC":"i","\u00ED":"i","\u00EE":"i","\u0129":"i","\u012B":"i","\u012D":"i","\u00EF":"i","\u1E2F":"i","\u1EC9":"i","\u01D0":"i","\u0209":"i","\u020B":"i","\u1ECB":"i","\u012F":"i","\u1E2D":"i","\u0268":"i","\u0131":"i","\u24D9":"j","\uFF4A":"j","\u0135":"j","\u01F0":"j","\u0249":"j","\u24DA":"k","\uFF4B":"k","\u1E31":"k","\u01E9":"k","\u1E33":"k","\u0137":"k","\u1E35":"k","\u0199":"k","\u2C6A":"k","\uA741":"k","\uA743":"k","\uA745":"k","\uA7A3":"k","\u24DB":"l","\uFF4C":"l","\u0140":"l","\u013A":"l","\u013E":"l","\u1E37":"l","\u1E39":"l","\u013C":"l","\u1E3D":"l","\u1E3B":"l","\u017F":"l","\u0142":"l","\u019A":"l","\u026B":"l","\u2C61":"l","\uA749":"l","\uA781":"l","\uA747":"l","\u01C9":"lj","\u24DC":"m","\uFF4D":"m","\u1E3F":"m","\u1E41":"m","\u1E43":"m","\u0271":"m","\u026F":"m","\u24DD":"n","\uFF4E":"n","\u01F9":"n","\u0144":"n","\u00F1":"n","\u1E45":"n","\u0148":"n","\u1E47":"n","\u0146":"n","\u1E4B":"n","\u1E49":"n","\u019E":"n","\u0272":"n","\u0149":"n","\uA791":"n","\uA7A5":"n","\u01CC":"nj","\u24DE":"o","\uFF4F":"o","\u00F2":"o","\u00F3":"o","\u00F4":"o","\u1ED3":"o","\u1ED1":"o","\u1ED7":"o","\u1ED5":"o","\u00F5":"o","\u1E4D":"o","\u022D":"o","\u1E4F":"o","\u014D":"o","\u1E51":"o","\u1E53":"o","\u014F":"o","\u022F":"o","\u0231":"o","\u00F6":"o","\u022B":"o","\u1ECF":"o","\u0151":"o","\u01D2":"o","\u020D":"o","\u020F":"o","\u01A1":"o","\u1EDD":"o","\u1EDB":"o","\u1EE1":"o","\u1EDF":"o","\u1EE3":"o","\u1ECD":"o","\u1ED9":"o","\u01EB":"o","\u01ED":"o","\u00F8":"o","\u01FF":"o","\u0254":"o","\uA74B":"o","\uA74D":"o","\u0275":"o","\u01A3":"oi","\u0223":"ou","\uA74F":"oo","\u24DF":"p","\uFF50":"p","\u1E55":"p","\u1E57":"p","\u01A5":"p","\u1D7D":"p","\uA751":"p","\uA753":"p","\uA755":"p","\u24E0":"q","\uFF51":"q","\u024B":"q","\uA757":"q","\uA759":"q","\u24E1":"r","\uFF52":"r","\u0155":"r","\u1E59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1E5B":"r","\u1E5D":"r","\u0157":"r","\u1E5F":"r","\u024D":"r","\u027D":"r","\uA75B":"r","\uA7A7":"r","\uA783":"r","\u24E2":"s","\uFF53":"s","\u00DF":"s","\u015B":"s","\u1E65":"s","\u015D":"s","\u1E61":"s","\u0161":"s","\u1E67":"s","\u1E63":"s","\u1E69":"s","\u0219":"s","\u015F":"s","\u023F":"s","\uA7A9":"s","\uA785":"s","\u1E9B":"s","\u24E3":"t","\uFF54":"t","\u1E6B":"t","\u1E97":"t","\u0165":"t","\u1E6D":"t","\u021B":"t","\u0163":"t","\u1E71":"t","\u1E6F":"t","\u0167":"t","\u01AD":"t","\u0288":"t","\u2C66":"t","\uA787":"t","\uA729":"tz","\u24E4":"u","\uFF55":"u","\u00F9":"u","\u00FA":"u","\u00FB":"u","\u0169":"u","\u1E79":"u","\u016B":"u","\u1E7B":"u","\u016D":"u","\u00FC":"u","\u01DC":"u","\u01D8":"u","\u01D6":"u","\u01DA":"u","\u1EE7":"u","\u016F":"u","\u0171":"u","\u01D4":"u","\u0215":"u","\u0217":"u","\u01B0":"u","\u1EEB":"u","\u1EE9":"u","\u1EEF":"u","\u1EED":"u","\u1EF1":"u","\u1EE5":"u","\u1E73":"u","\u0173":"u","\u1E77":"u","\u1E75":"u","\u0289":"u","\u24E5":"v","\uFF56":"v","\u1E7D":"v","\u1E7F":"v","\u028B":"v","\uA75F":"v","\u028C":"v","\uA761":"vy","\u24E6":"w","\uFF57":"w","\u1E81":"w","\u1E83":"w","\u0175":"w","\u1E87":"w","\u1E85":"w","\u1E98":"w","\u1E89":"w","\u2C73":"w","\u24E7":"x","\uFF58":"x","\u1E8B":"x","\u1E8D":"x","\u24E8":"y","\uFF59":"y","\u1EF3":"y","\u00FD":"y","\u0177":"y","\u1EF9":"y","\u0233":"y","\u1E8F":"y","\u00FF":"y","\u1EF7":"y","\u1E99":"y","\u1EF5":"y","\u01B4":"y","\u024F":"y","\u1EFF":"y","\u24E9":"z","\uFF5A":"z","\u017A":"z","\u1E91":"z","\u017C":"z","\u017E":"z","\u1E93":"z","\u1E95":"z","\u01B6":"z","\u0225":"z","\u0240":"z","\u2C6C":"z","\uA763":"z","\u0386":"\u0391","\u0388":"\u0395","\u0389":"\u0397","\u038A":"\u0399","\u03AA":"\u0399","\u038C":"\u039F","\u038E":"\u03A5","\u03AB":"\u03A5","\u038F":"\u03A9","\u03AC":"\u03B1","\u03AD":"\u03B5","\u03AE":"\u03B7","\u03AF":"\u03B9","\u03CA":"\u03B9","\u0390":"\u03B9","\u03CC":"\u03BF","\u03CD":"\u03C5","\u03CB":"\u03C5","\u03B0":"\u03C5","\u03C9":"\u03C9","\u03C2":"\u03C3"};
102
+
103
+ $document = $(document);
104
+
105
+ nextUid=(function() { var counter=1; return function() { return counter++; }; }());
106
+
107
+
108
+ function reinsertElement(element) {
109
+ var placeholder = $(document.createTextNode(''));
110
+
111
+ element.before(placeholder);
112
+ placeholder.before(element);
113
+ placeholder.remove();
114
+ }
115
+
116
+ function stripDiacritics(str) {
117
+ // Used 'uni range + named function' from http://jsperf.com/diacritics/18
118
+ function match(a) {
119
+ return DIACRITICS[a] || a;
120
+ }
121
+
122
+ return str.replace(/[^\u0000-\u007E]/g, match);
123
+ }
124
+
125
+ function indexOf(value, array) {
126
+ var i = 0, l = array.length;
127
+ for (; i < l; i = i + 1) {
128
+ if (equal(value, array[i])) return i;
129
+ }
130
+ return -1;
131
+ }
132
+
133
+ function measureScrollbar () {
134
+ var $template = $( MEASURE_SCROLLBAR_TEMPLATE );
135
+ $template.appendTo(document.body);
136
+
137
+ var dim = {
138
+ width: $template.width() - $template[0].clientWidth,
139
+ height: $template.height() - $template[0].clientHeight
140
+ };
141
+ $template.remove();
142
+
143
+ return dim;
144
+ }
145
+
146
+ /**
147
+ * Compares equality of a and b
148
+ * @param a
149
+ * @param b
150
+ */
151
+ function equal(a, b) {
152
+ if (a === b) return true;
153
+ if (a === undefined || b === undefined) return false;
154
+ if (a === null || b === null) return false;
155
+ // Check whether 'a' or 'b' is a string (primitive or object).
156
+ // The concatenation of an empty string (+'') converts its argument to a string's primitive.
157
+ if (a.constructor === String) return a+'' === b+''; // a+'' - in case 'a' is a String object
158
+ if (b.constructor === String) return b+'' === a+''; // b+'' - in case 'b' is a String object
159
+ return false;
160
+ }
161
+
162
+ /**
163
+ * Splits the string into an array of values, transforming each value. An empty array is returned for nulls or empty
164
+ * strings
165
+ * @param string
166
+ * @param separator
167
+ */
168
+ function splitVal(string, separator, transform) {
169
+ var val, i, l;
170
+ if (string === null || string.length < 1) return [];
171
+ val = string.split(separator);
172
+ for (i = 0, l = val.length; i < l; i = i + 1) val[i] = transform(val[i]);
173
+ return val;
174
+ }
175
+
176
+ function getSideBorderPadding(element) {
177
+ return element.outerWidth(false) - element.width();
178
+ }
179
+
180
+ function installKeyUpChangeEvent(element) {
181
+ var key="keyup-change-value";
182
+ element.on("keydown", function () {
183
+ if ($.data(element, key) === undefined) {
184
+ $.data(element, key, element.val());
185
+ }
186
+ });
187
+ element.on("keyup", function () {
188
+ var val= $.data(element, key);
189
+ if (val !== undefined && element.val() !== val) {
190
+ $.removeData(element, key);
191
+ element.trigger("keyup-change");
192
+ }
193
+ });
194
+ }
195
+
196
+
197
+ /**
198
+ * filters mouse events so an event is fired only if the mouse moved.
199
+ *
200
+ * filters out mouse events that occur when mouse is stationary but
201
+ * the elements under the pointer are scrolled.
202
+ */
203
+ function installFilteredMouseMove(element) {
204
+ element.on("mousemove", function (e) {
205
+ var lastpos = lastMousePosition;
206
+ if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) {
207
+ $(e.target).trigger("mousemove-filtered", e);
208
+ }
209
+ });
210
+ }
211
+
212
+ /**
213
+ * Debounces a function. Returns a function that calls the original fn function only if no invocations have been made
214
+ * within the last quietMillis milliseconds.
215
+ *
216
+ * @param quietMillis number of milliseconds to wait before invoking fn
217
+ * @param fn function to be debounced
218
+ * @param ctx object to be used as this reference within fn
219
+ * @return debounced version of fn
220
+ */
221
+ function debounce(quietMillis, fn, ctx) {
222
+ ctx = ctx || undefined;
223
+ var timeout;
224
+ return function () {
225
+ var args = arguments;
226
+ window.clearTimeout(timeout);
227
+ timeout = window.setTimeout(function() {
228
+ fn.apply(ctx, args);
229
+ }, quietMillis);
230
+ };
231
+ }
232
+
233
+ function installDebouncedScroll(threshold, element) {
234
+ var notify = debounce(threshold, function (e) { element.trigger("scroll-debounced", e);});
235
+ element.on("scroll", function (e) {
236
+ if (indexOf(e.target, element.get()) >= 0) notify(e);
237
+ });
238
+ }
239
+
240
+ function focus($el) {
241
+ if ($el[0] === document.activeElement) return;
242
+
243
+ /* set the focus in a 0 timeout - that way the focus is set after the processing
244
+ of the current event has finished - which seems like the only reliable way
245
+ to set focus */
246
+ window.setTimeout(function() {
247
+ var el=$el[0], pos=$el.val().length, range;
248
+
249
+ $el.focus();
250
+
251
+ /* make sure el received focus so we do not error out when trying to manipulate the caret.
252
+ sometimes modals or others listeners may steal it after its set */
253
+ var isVisible = (el.offsetWidth > 0 || el.offsetHeight > 0);
254
+ if (isVisible && el === document.activeElement) {
255
+
256
+ /* after the focus is set move the caret to the end, necessary when we val()
257
+ just before setting focus */
258
+ if(el.setSelectionRange)
259
+ {
260
+ el.setSelectionRange(pos, pos);
261
+ }
262
+ else if (el.createTextRange) {
263
+ range = el.createTextRange();
264
+ range.collapse(false);
265
+ range.select();
266
+ }
267
+ }
268
+ }, 0);
269
+ }
270
+
271
+ function getCursorInfo(el) {
272
+ el = $(el)[0];
273
+ var offset = 0;
274
+ var length = 0;
275
+ if ('selectionStart' in el) {
276
+ offset = el.selectionStart;
277
+ length = el.selectionEnd - offset;
278
+ } else if ('selection' in document) {
279
+ el.focus();
280
+ var sel = document.selection.createRange();
281
+ length = document.selection.createRange().text.length;
282
+ sel.moveStart('character', -el.value.length);
283
+ offset = sel.text.length - length;
284
+ }
285
+ return { offset: offset, length: length };
286
+ }
287
+
288
+ function killEvent(event) {
289
+ event.preventDefault();
290
+ event.stopPropagation();
291
+ }
292
+ function killEventImmediately(event) {
293
+ event.preventDefault();
294
+ event.stopImmediatePropagation();
295
+ }
296
+
297
+ function measureTextWidth(e) {
298
+ if (!sizer){
299
+ var style = e[0].currentStyle || window.getComputedStyle(e[0], null);
300
+ sizer = $(document.createElement("div")).css({
301
+ position: "absolute",
302
+ left: "-10000px",
303
+ top: "-10000px",
304
+ display: "none",
305
+ fontSize: style.fontSize,
306
+ fontFamily: style.fontFamily,
307
+ fontStyle: style.fontStyle,
308
+ fontWeight: style.fontWeight,
309
+ letterSpacing: style.letterSpacing,
310
+ textTransform: style.textTransform,
311
+ whiteSpace: "nowrap"
312
+ });
313
+ sizer.attr("class","select2-sizer");
314
+ $(document.body).append(sizer);
315
+ }
316
+ sizer.text(e.val());
317
+ return sizer.width();
318
+ }
319
+
320
+ function syncCssClasses(dest, src, adapter) {
321
+ var classes, replacements = [], adapted;
322
+
323
+ classes = $.trim(dest.attr("class"));
324
+
325
+ if (classes) {
326
+ classes = '' + classes; // for IE which returns object
327
+
328
+ $(classes.split(/\s+/)).each2(function() {
329
+ if (this.indexOf("select2-") === 0) {
330
+ replacements.push(this);
331
+ }
332
+ });
333
+ }
334
+
335
+ classes = $.trim(src.attr("class"));
336
+
337
+ if (classes) {
338
+ classes = '' + classes; // for IE which returns object
339
+
340
+ $(classes.split(/\s+/)).each2(function() {
341
+ if (this.indexOf("select2-") !== 0) {
342
+ adapted = adapter(this);
343
+
344
+ if (adapted) {
345
+ replacements.push(adapted);
346
+ }
347
+ }
348
+ });
349
+ }
350
+
351
+ dest.attr("class", replacements.join(" "));
352
+ }
353
+
354
+
355
+ function markMatch(text, term, markup, escapeMarkup) {
356
+ var match=stripDiacritics(text.toUpperCase()).indexOf(stripDiacritics(term.toUpperCase())),
357
+ tl=term.length;
358
+
359
+ if (match<0) {
360
+ markup.push(escapeMarkup(text));
361
+ return;
362
+ }
363
+
364
+ markup.push(escapeMarkup(text.substring(0, match)));
365
+ markup.push("<span class='select2-match'>");
366
+ markup.push(escapeMarkup(text.substring(match, match + tl)));
367
+ markup.push("</span>");
368
+ markup.push(escapeMarkup(text.substring(match + tl, text.length)));
369
+ }
370
+
371
+ function defaultEscapeMarkup(markup) {
372
+ var replace_map = {
373
+ '\\': '&#92;',
374
+ '&': '&amp;',
375
+ '<': '&lt;',
376
+ '>': '&gt;',
377
+ '"': '&quot;',
378
+ "'": '&#39;',
379
+ "/": '&#47;'
380
+ };
381
+
382
+ return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
383
+ return replace_map[match];
384
+ });
385
+ }
386
+
387
+ /**
388
+ * Produces an ajax-based query function
389
+ *
390
+ * @param options object containing configuration parameters
391
+ * @param options.params parameter map for the transport ajax call, can contain such options as cache, jsonpCallback, etc. see $.ajax
392
+ * @param options.transport function that will be used to execute the ajax request. must be compatible with parameters supported by $.ajax
393
+ * @param options.url url for the data
394
+ * @param options.data a function(searchTerm, pageNumber, context) that should return an object containing query string parameters for the above url.
395
+ * @param options.dataType request data type: ajax, jsonp, other datatypes supported by jQuery's $.ajax function or the transport function if specified
396
+ * @param options.quietMillis (optional) milliseconds to wait before making the ajaxRequest, helps debounce the ajax function if invoked too often
397
+ * @param options.results a function(remoteData, pageNumber, query) that converts data returned form the remote request to the format expected by Select2.
398
+ * The expected format is an object containing the following keys:
399
+ * results array of objects that will be used as choices
400
+ * more (optional) boolean indicating whether there are more results available
401
+ * Example: {results:[{id:1, text:'Red'},{id:2, text:'Blue'}], more:true}
402
+ */
403
+ function ajax(options) {
404
+ var timeout, // current scheduled but not yet executed request
405
+ handler = null,
406
+ quietMillis = options.quietMillis || 100,
407
+ ajaxUrl = options.url,
408
+ self = this;
409
+
410
+ return function (query) {
411
+ window.clearTimeout(timeout);
412
+ timeout = window.setTimeout(function () {
413
+ var data = options.data, // ajax data function
414
+ url = ajaxUrl, // ajax url string or function
415
+ transport = options.transport || $.fn.select2.ajaxDefaults.transport,
416
+ // deprecated - to be removed in 4.0 - use params instead
417
+ deprecated = {
418
+ type: options.type || 'GET', // set type of request (GET or POST)
419
+ cache: options.cache || false,
420
+ jsonpCallback: options.jsonpCallback||undefined,
421
+ dataType: options.dataType||"json"
422
+ },
423
+ params = $.extend({}, $.fn.select2.ajaxDefaults.params, deprecated);
424
+
425
+ data = data ? data.call(self, query.term, query.page, query.context) : null;
426
+ url = (typeof url === 'function') ? url.call(self, query.term, query.page, query.context) : url;
427
+
428
+ if (handler && typeof handler.abort === "function") { handler.abort(); }
429
+
430
+ if (options.params) {
431
+ if ($.isFunction(options.params)) {
432
+ $.extend(params, options.params.call(self));
433
+ } else {
434
+ $.extend(params, options.params);
435
+ }
436
+ }
437
+
438
+ $.extend(params, {
439
+ url: url,
440
+ dataType: options.dataType,
441
+ data: data,
442
+ success: function (data) {
443
+ // TODO - replace query.page with query so users have access to term, page, etc.
444
+ // added query as third paramter to keep backwards compatibility
445
+ var results = options.results(data, query.page, query);
446
+ query.callback(results);
447
+ },
448
+ error: function(jqXHR, textStatus, errorThrown){
449
+ var results = {
450
+ hasError: true,
451
+ jqXHR: jqXHR,
452
+ textStatus: textStatus,
453
+ errorThrown: errorThrown
454
+ };
455
+
456
+ query.callback(results);
457
+ }
458
+ });
459
+ handler = transport.call(self, params);
460
+ }, quietMillis);
461
+ };
462
+ }
463
+
464
+ /**
465
+ * Produces a query function that works with a local array
466
+ *
467
+ * @param options object containing configuration parameters. The options parameter can either be an array or an
468
+ * object.
469
+ *
470
+ * If the array form is used it is assumed that it contains objects with 'id' and 'text' keys.
471
+ *
472
+ * If the object form is used it is assumed that it contains 'data' and 'text' keys. The 'data' key should contain
473
+ * an array of objects that will be used as choices. These objects must contain at least an 'id' key. The 'text'
474
+ * key can either be a String in which case it is expected that each element in the 'data' array has a key with the
475
+ * value of 'text' which will be used to match choices. Alternatively, text can be a function(item) that can extract
476
+ * the text.
477
+ */
478
+ function local(options) {
479
+ var data = options, // data elements
480
+ dataText,
481
+ tmp,
482
+ text = function (item) { return ""+item.text; }; // function used to retrieve the text portion of a data item that is matched against the search
483
+
484
+ if ($.isArray(data)) {
485
+ tmp = data;
486
+ data = { results: tmp };
487
+ }
488
+
489
+ if ($.isFunction(data) === false) {
490
+ tmp = data;
491
+ data = function() { return tmp; };
492
+ }
493
+
494
+ var dataItem = data();
495
+ if (dataItem.text) {
496
+ text = dataItem.text;
497
+ // if text is not a function we assume it to be a key name
498
+ if (!$.isFunction(text)) {
499
+ dataText = dataItem.text; // we need to store this in a separate variable because in the next step data gets reset and data.text is no longer available
500
+ text = function (item) { return item[dataText]; };
501
+ }
502
+ }
503
+
504
+ return function (query) {
505
+ var t = query.term, filtered = { results: [] }, process;
506
+ if (t === "") {
507
+ query.callback(data());
508
+ return;
509
+ }
510
+
511
+ process = function(datum, collection) {
512
+ var group, attr;
513
+ datum = datum[0];
514
+ if (datum.children) {
515
+ group = {};
516
+ for (attr in datum) {
517
+ if (datum.hasOwnProperty(attr)) group[attr]=datum[attr];
518
+ }
519
+ group.children=[];
520
+ $(datum.children).each2(function(i, childDatum) { process(childDatum, group.children); });
521
+ if (group.children.length || query.matcher(t, text(group), datum)) {
522
+ collection.push(group);
523
+ }
524
+ } else {
525
+ if (query.matcher(t, text(datum), datum)) {
526
+ collection.push(datum);
527
+ }
528
+ }
529
+ };
530
+
531
+ $(data().results).each2(function(i, datum) { process(datum, filtered.results); });
532
+ query.callback(filtered);
533
+ };
534
+ }
535
+
536
+ // TODO javadoc
537
+ function tags(data) {
538
+ var isFunc = $.isFunction(data);
539
+ return function (query) {
540
+ var t = query.term, filtered = {results: []};
541
+ var result = isFunc ? data(query) : data;
542
+ if ($.isArray(result)) {
543
+ $(result).each(function () {
544
+ var isObject = this.text !== undefined,
545
+ text = isObject ? this.text : this;
546
+ if (t === "" || query.matcher(t, text)) {
547
+ filtered.results.push(isObject ? this : {id: this, text: this});
548
+ }
549
+ });
550
+ query.callback(filtered);
551
+ }
552
+ };
553
+ }
554
+
555
+ /**
556
+ * Checks if the formatter function should be used.
557
+ *
558
+ * Throws an error if it is not a function. Returns true if it should be used,
559
+ * false if no formatting should be performed.
560
+ *
561
+ * @param formatter
562
+ */
563
+ function checkFormatter(formatter, formatterName) {
564
+ if ($.isFunction(formatter)) return true;
565
+ if (!formatter) return false;
566
+ if (typeof(formatter) === 'string') return true;
567
+ throw new Error(formatterName +" must be a string, function, or falsy value");
568
+ }
569
+
570
+ /**
571
+ * Returns a given value
572
+ * If given a function, returns its output
573
+ *
574
+ * @param val string|function
575
+ * @param context value of "this" to be passed to function
576
+ * @returns {*}
577
+ */
578
+ function evaluate(val, context) {
579
+ if ($.isFunction(val)) {
580
+ var args = Array.prototype.slice.call(arguments, 2);
581
+ return val.apply(context, args);
582
+ }
583
+ return val;
584
+ }
585
+
586
+ function countResults(results) {
587
+ var count = 0;
588
+ $.each(results, function(i, item) {
589
+ if (item.children) {
590
+ count += countResults(item.children);
591
+ } else {
592
+ count++;
593
+ }
594
+ });
595
+ return count;
596
+ }
597
+
598
+ /**
599
+ * Default tokenizer. This function uses breaks the input on substring match of any string from the
600
+ * opts.tokenSeparators array and uses opts.createSearchChoice to create the choice object. Both of those
601
+ * two options have to be defined in order for the tokenizer to work.
602
+ *
603
+ * @param input text user has typed so far or pasted into the search field
604
+ * @param selection currently selected choices
605
+ * @param selectCallback function(choice) callback tho add the choice to selection
606
+ * @param opts select2's opts
607
+ * @return undefined/null to leave the current input unchanged, or a string to change the input to the returned value
608
+ */
609
+ function defaultTokenizer(input, selection, selectCallback, opts) {
610
+ var original = input, // store the original so we can compare and know if we need to tell the search to update its text
611
+ dupe = false, // check for whether a token we extracted represents a duplicate selected choice
612
+ token, // token
613
+ index, // position at which the separator was found
614
+ i, l, // looping variables
615
+ separator; // the matched separator
616
+
617
+ if (!opts.createSearchChoice || !opts.tokenSeparators || opts.tokenSeparators.length < 1) return undefined;
618
+
619
+ while (true) {
620
+ index = -1;
621
+
622
+ for (i = 0, l = opts.tokenSeparators.length; i < l; i++) {
623
+ separator = opts.tokenSeparators[i];
624
+ index = input.indexOf(separator);
625
+ if (index >= 0) break;
626
+ }
627
+
628
+ if (index < 0) break; // did not find any token separator in the input string, bail
629
+
630
+ token = input.substring(0, index);
631
+ input = input.substring(index + separator.length);
632
+
633
+ if (token.length > 0) {
634
+ token = opts.createSearchChoice.call(this, token, selection);
635
+ if (token !== undefined && token !== null && opts.id(token) !== undefined && opts.id(token) !== null) {
636
+ dupe = false;
637
+ for (i = 0, l = selection.length; i < l; i++) {
638
+ if (equal(opts.id(token), opts.id(selection[i]))) {
639
+ dupe = true; break;
640
+ }
641
+ }
642
+
643
+ if (!dupe) selectCallback(token);
644
+ }
645
+ }
646
+ }
647
+
648
+ if (original!==input) return input;
649
+ }
650
+
651
+ function cleanupJQueryElements() {
652
+ var self = this;
653
+
654
+ $.each(arguments, function (i, element) {
655
+ self[element].remove();
656
+ self[element] = null;
657
+ });
658
+ }
659
+
660
+ /**
661
+ * Creates a new class
662
+ *
663
+ * @param superClass
664
+ * @param methods
665
+ */
666
+ function clazz(SuperClass, methods) {
667
+ var constructor = function () {};
668
+ constructor.prototype = new SuperClass;
669
+ constructor.prototype.constructor = constructor;
670
+ constructor.prototype.parent = SuperClass.prototype;
671
+ constructor.prototype = $.extend(constructor.prototype, methods);
672
+ return constructor;
673
+ }
674
+
675
+ AbstractSelect2 = clazz(Object, {
676
+
677
+ // abstract
678
+ bind: function (func) {
679
+ var self = this;
680
+ return function () {
681
+ func.apply(self, arguments);
682
+ };
683
+ },
684
+
685
+ // abstract
686
+ init: function (opts) {
687
+ var results, search, resultsSelector = ".select2-results";
688
+
689
+ // prepare options
690
+ this.opts = opts = this.prepareOpts(opts);
691
+
692
+ this.id=opts.id;
693
+
694
+ // destroy if called on an existing component
695
+ if (opts.element.data("select2") !== undefined &&
696
+ opts.element.data("select2") !== null) {
697
+ opts.element.data("select2").destroy();
698
+ }
699
+
700
+ this.container = this.createContainer();
701
+
702
+ this.liveRegion = $('.select2-hidden-accessible');
703
+ if (this.liveRegion.length == 0) {
704
+ this.liveRegion = $("<span>", {
705
+ role: "status",
706
+ "aria-live": "polite"
707
+ })
708
+ .addClass("select2-hidden-accessible")
709
+ .appendTo(document.body);
710
+ }
711
+
712
+ this.containerId="s2id_"+(opts.element.attr("id") || "autogen"+nextUid());
713
+ this.containerEventName= this.containerId
714
+ .replace(/([.])/g, '_')
715
+ .replace(/([;&,\-\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1');
716
+ this.container.attr("id", this.containerId);
717
+
718
+ this.container.attr("title", opts.element.attr("title"));
719
+
720
+ this.body = $(document.body);
721
+
722
+ syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
723
+
724
+ this.container.attr("style", opts.element.attr("style"));
725
+ this.container.css(evaluate(opts.containerCss, this.opts.element));
726
+ this.container.addClass(evaluate(opts.containerCssClass, this.opts.element));
727
+
728
+ this.elementTabIndex = this.opts.element.attr("tabindex");
729
+
730
+ // swap container for the element
731
+ this.opts.element
732
+ .data("select2", this)
733
+ .attr("tabindex", "-1")
734
+ .before(this.container)
735
+ .on("click.select2", killEvent); // do not leak click events
736
+
737
+ this.container.data("select2", this);
738
+
739
+ this.dropdown = this.container.find(".select2-drop");
740
+
741
+ syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
742
+
743
+ this.dropdown.addClass(evaluate(opts.dropdownCssClass, this.opts.element));
744
+ this.dropdown.data("select2", this);
745
+ this.dropdown.on("click", killEvent);
746
+
747
+ this.results = results = this.container.find(resultsSelector);
748
+ this.search = search = this.container.find("input.select2-input");
749
+
750
+ this.queryCount = 0;
751
+ this.resultsPage = 0;
752
+ this.context = null;
753
+
754
+ // initialize the container
755
+ this.initContainer();
756
+
757
+ this.container.on("click", killEvent);
758
+
759
+ installFilteredMouseMove(this.results);
760
+
761
+ this.dropdown.on("mousemove-filtered", resultsSelector, this.bind(this.highlightUnderEvent));
762
+ this.dropdown.on("touchstart touchmove touchend", resultsSelector, this.bind(function (event) {
763
+ this._touchEvent = true;
764
+ this.highlightUnderEvent(event);
765
+ }));
766
+ this.dropdown.on("touchmove", resultsSelector, this.bind(this.touchMoved));
767
+ this.dropdown.on("touchstart touchend", resultsSelector, this.bind(this.clearTouchMoved));
768
+
769
+ // Waiting for a click event on touch devices to select option and hide dropdown
770
+ // otherwise click will be triggered on an underlying element
771
+ this.dropdown.on('click', this.bind(function (event) {
772
+ if (this._touchEvent) {
773
+ this._touchEvent = false;
774
+ this.selectHighlighted();
775
+ }
776
+ }));
777
+
778
+ installDebouncedScroll(80, this.results);
779
+ this.dropdown.on("scroll-debounced", resultsSelector, this.bind(this.loadMoreIfNeeded));
780
+
781
+ // do not propagate change event from the search field out of the component
782
+ $(this.container).on("change", ".select2-input", function(e) {e.stopPropagation();});
783
+ $(this.dropdown).on("change", ".select2-input", function(e) {e.stopPropagation();});
784
+
785
+ // if jquery.mousewheel plugin is installed we can prevent out-of-bounds scrolling of results via mousewheel
786
+ if ($.fn.mousewheel) {
787
+ results.mousewheel(function (e, delta, deltaX, deltaY) {
788
+ var top = results.scrollTop();
789
+ if (deltaY > 0 && top - deltaY <= 0) {
790
+ results.scrollTop(0);
791
+ killEvent(e);
792
+ } else if (deltaY < 0 && results.get(0).scrollHeight - results.scrollTop() + deltaY <= results.height()) {
793
+ results.scrollTop(results.get(0).scrollHeight - results.height());
794
+ killEvent(e);
795
+ }
796
+ });
797
+ }
798
+
799
+ installKeyUpChangeEvent(search);
800
+ search.on("keyup-change input paste", this.bind(this.updateResults));
801
+ search.on("focus", function () { search.addClass("select2-focused"); });
802
+ search.on("blur", function () { search.removeClass("select2-focused");});
803
+
804
+ this.dropdown.on("mouseup", resultsSelector, this.bind(function (e) {
805
+ if ($(e.target).closest(".select2-result-selectable").length > 0) {
806
+ this.highlightUnderEvent(e);
807
+ this.selectHighlighted(e);
808
+ }
809
+ }));
810
+
811
+ // trap all mouse events from leaving the dropdown. sometimes there may be a modal that is listening
812
+ // for mouse events outside of itself so it can close itself. since the dropdown is now outside the select2's
813
+ // dom it will trigger the popup close, which is not what we want
814
+ // focusin can cause focus wars between modals and select2 since the dropdown is outside the modal.
815
+ this.dropdown.on("click mouseup mousedown touchstart touchend focusin", function (e) { e.stopPropagation(); });
816
+
817
+ this.nextSearchTerm = undefined;
818
+
819
+ if ($.isFunction(this.opts.initSelection)) {
820
+ // initialize selection based on the current value of the source element
821
+ this.initSelection();
822
+
823
+ // if the user has provided a function that can set selection based on the value of the source element
824
+ // we monitor the change event on the element and trigger it, allowing for two way synchronization
825
+ this.monitorSource();
826
+ }
827
+
828
+ if (opts.maximumInputLength !== null) {
829
+ this.search.attr("maxlength", opts.maximumInputLength);
830
+ }
831
+
832
+ var disabled = opts.element.prop("disabled");
833
+ if (disabled === undefined) disabled = false;
834
+ this.enable(!disabled);
835
+
836
+ var readonly = opts.element.prop("readonly");
837
+ if (readonly === undefined) readonly = false;
838
+ this.readonly(readonly);
839
+
840
+ // Calculate size of scrollbar
841
+ scrollBarDimensions = scrollBarDimensions || measureScrollbar();
842
+
843
+ this.autofocus = opts.element.prop("autofocus");
844
+ opts.element.prop("autofocus", false);
845
+ if (this.autofocus) this.focus();
846
+
847
+ this.search.attr("placeholder", opts.searchInputPlaceholder);
848
+ },
849
+
850
+ // abstract
851
+ destroy: function () {
852
+ var element=this.opts.element, select2 = element.data("select2"), self = this;
853
+
854
+ this.close();
855
+
856
+ if (element.length && element[0].detachEvent && self._sync) {
857
+ element.each(function () {
858
+ if (self._sync) {
859
+ this.detachEvent("onpropertychange", self._sync);
860
+ }
861
+ });
862
+ }
863
+ if (this.propertyObserver) {
864
+ this.propertyObserver.disconnect();
865
+ this.propertyObserver = null;
866
+ }
867
+ this._sync = null;
868
+
869
+ if (select2 !== undefined) {
870
+ select2.container.remove();
871
+ select2.liveRegion.remove();
872
+ select2.dropdown.remove();
873
+ element
874
+ .show()
875
+ .removeData("select2")
876
+ .off(".select2")
877
+ .prop("autofocus", this.autofocus || false);
878
+ if (this.elementTabIndex) {
879
+ element.attr({tabindex: this.elementTabIndex});
880
+ } else {
881
+ element.removeAttr("tabindex");
882
+ }
883
+ element.show();
884
+ }
885
+
886
+ cleanupJQueryElements.call(this,
887
+ "container",
888
+ "liveRegion",
889
+ "dropdown",
890
+ "results",
891
+ "search"
892
+ );
893
+ },
894
+
895
+ // abstract
896
+ optionToData: function(element) {
897
+ if (element.is("option")) {
898
+ return {
899
+ id:element.prop("value"),
900
+ text:element.text(),
901
+ element: element.get(),
902
+ css: element.attr("class"),
903
+ disabled: element.prop("disabled"),
904
+ locked: equal(element.attr("locked"), "locked") || equal(element.data("locked"), true)
905
+ };
906
+ } else if (element.is("optgroup")) {
907
+ return {
908
+ text:element.attr("label"),
909
+ children:[],
910
+ element: element.get(),
911
+ css: element.attr("class")
912
+ };
913
+ }
914
+ },
915
+
916
+ // abstract
917
+ prepareOpts: function (opts) {
918
+ var element, select, idKey, ajaxUrl, self = this;
919
+
920
+ element = opts.element;
921
+
922
+ if (element.get(0).tagName.toLowerCase() === "select") {
923
+ this.select = select = opts.element;
924
+ }
925
+
926
+ if (select) {
927
+ // these options are not allowed when attached to a select because they are picked up off the element itself
928
+ $.each(["id", "multiple", "ajax", "query", "createSearchChoice", "initSelection", "data", "tags"], function () {
929
+ if (this in opts) {
930
+ throw new Error("Option '" + this + "' is not allowed for Select2 when attached to a <select> element.");
931
+ }
932
+ });
933
+ }
934
+
935
+ opts = $.extend({}, {
936
+ populateResults: function(container, results, query) {
937
+ var populate, id=this.opts.id, liveRegion=this.liveRegion;
938
+
939
+ populate=function(results, container, depth) {
940
+
941
+ var i, l, result, selectable, disabled, compound, node, label, innerContainer, formatted;
942
+
943
+ results = opts.sortResults(results, container, query);
944
+
945
+ // collect the created nodes for bulk append
946
+ var nodes = [];
947
+ for (i = 0, l = results.length; i < l; i = i + 1) {
948
+
949
+ result=results[i];
950
+
951
+ disabled = (result.disabled === true);
952
+ selectable = (!disabled) && (id(result) !== undefined);
953
+
954
+ compound=result.children && result.children.length > 0;
955
+
956
+ node=$("<li></li>");
957
+ node.addClass("select2-results-dept-"+depth);
958
+ node.addClass("select2-result");
959
+ node.addClass(selectable ? "select2-result-selectable" : "select2-result-unselectable");
960
+ if (disabled) { node.addClass("select2-disabled"); }
961
+ if (compound) { node.addClass("select2-result-with-children"); }
962
+ node.addClass(self.opts.formatResultCssClass(result));
963
+ node.attr("role", "presentation");
964
+
965
+ label=$(document.createElement("div"));
966
+ label.addClass("select2-result-label");
967
+ label.attr("id", "select2-result-label-" + nextUid());
968
+ label.attr("role", "option");
969
+
970
+ formatted=opts.formatResult(result, label, query, self.opts.escapeMarkup);
971
+ if (formatted!==undefined) {
972
+ label.html(formatted);
973
+ node.append(label);
974
+ }
975
+
976
+
977
+ if (compound) {
978
+
979
+ innerContainer=$("<ul></ul>");
980
+ innerContainer.addClass("select2-result-sub");
981
+ populate(result.children, innerContainer, depth+1);
982
+ node.append(innerContainer);
983
+ }
984
+
985
+ node.data("select2-data", result);
986
+ nodes.push(node[0]);
987
+ }
988
+
989
+ // bulk append the created nodes
990
+ container.append(nodes);
991
+ liveRegion.text(opts.formatMatches(results.length));
992
+ };
993
+
994
+ populate(results, container, 0);
995
+ }
996
+ }, $.fn.select2.defaults, opts);
997
+
998
+ if (typeof(opts.id) !== "function") {
999
+ idKey = opts.id;
1000
+ opts.id = function (e) { return e[idKey]; };
1001
+ }
1002
+
1003
+ if ($.isArray(opts.element.data("select2Tags"))) {
1004
+ if ("tags" in opts) {
1005
+ throw "tags specified as both an attribute 'data-select2-tags' and in options of Select2 " + opts.element.attr("id");
1006
+ }
1007
+ opts.tags=opts.element.data("select2Tags");
1008
+ }
1009
+
1010
+ if (select) {
1011
+ opts.query = this.bind(function (query) {
1012
+ var data = { results: [], more: false },
1013
+ term = query.term,
1014
+ children, placeholderOption, process;
1015
+
1016
+ process=function(element, collection) {
1017
+ var group;
1018
+ if (element.is("option")) {
1019
+ if (query.matcher(term, element.text(), element)) {
1020
+ collection.push(self.optionToData(element));
1021
+ }
1022
+ } else if (element.is("optgroup")) {
1023
+ group=self.optionToData(element);
1024
+ element.children().each2(function(i, elm) { process(elm, group.children); });
1025
+ if (group.children.length>0) {
1026
+ collection.push(group);
1027
+ }
1028
+ }
1029
+ };
1030
+
1031
+ children=element.children();
1032
+
1033
+ // ignore the placeholder option if there is one
1034
+ if (this.getPlaceholder() !== undefined && children.length > 0) {
1035
+ placeholderOption = this.getPlaceholderOption();
1036
+ if (placeholderOption) {
1037
+ children=children.not(placeholderOption);
1038
+ }
1039
+ }
1040
+
1041
+ children.each2(function(i, elm) { process(elm, data.results); });
1042
+
1043
+ query.callback(data);
1044
+ });
1045
+ // this is needed because inside val() we construct choices from options and their id is hardcoded
1046
+ opts.id=function(e) { return e.id; };
1047
+ } else {
1048
+ if (!("query" in opts)) {
1049
+
1050
+ if ("ajax" in opts) {
1051
+ ajaxUrl = opts.element.data("ajax-url");
1052
+ if (ajaxUrl && ajaxUrl.length > 0) {
1053
+ opts.ajax.url = ajaxUrl;
1054
+ }
1055
+ opts.query = ajax.call(opts.element, opts.ajax);
1056
+ } else if ("data" in opts) {
1057
+ opts.query = local(opts.data);
1058
+ } else if ("tags" in opts) {
1059
+ opts.query = tags(opts.tags);
1060
+ if (opts.createSearchChoice === undefined) {
1061
+ opts.createSearchChoice = function (term) { return {id: $.trim(term), text: $.trim(term)}; };
1062
+ }
1063
+ if (opts.initSelection === undefined) {
1064
+ opts.initSelection = function (element, callback) {
1065
+ var data = [];
1066
+ $(splitVal(element.val(), opts.separator, opts.transformVal)).each(function () {
1067
+ var obj = { id: this, text: this },
1068
+ tags = opts.tags;
1069
+ if ($.isFunction(tags)) tags=tags();
1070
+ $(tags).each(function() { if (equal(this.id, obj.id)) { obj = this; return false; } });
1071
+ data.push(obj);
1072
+ });
1073
+
1074
+ callback(data);
1075
+ };
1076
+ }
1077
+ }
1078
+ }
1079
+ }
1080
+ if (typeof(opts.query) !== "function") {
1081
+ throw "query function not defined for Select2 " + opts.element.attr("id");
1082
+ }
1083
+
1084
+ if (opts.createSearchChoicePosition === 'top') {
1085
+ opts.createSearchChoicePosition = function(list, item) { list.unshift(item); };
1086
+ }
1087
+ else if (opts.createSearchChoicePosition === 'bottom') {
1088
+ opts.createSearchChoicePosition = function(list, item) { list.push(item); };
1089
+ }
1090
+ else if (typeof(opts.createSearchChoicePosition) !== "function") {
1091
+ throw "invalid createSearchChoicePosition option must be 'top', 'bottom' or a custom function";
1092
+ }
1093
+
1094
+ return opts;
1095
+ },
1096
+
1097
+ /**
1098
+ * Monitor the original element for changes and update select2 accordingly
1099
+ */
1100
+ // abstract
1101
+ monitorSource: function () {
1102
+ var el = this.opts.element, observer, self = this;
1103
+
1104
+ el.on("change.select2", this.bind(function (e) {
1105
+ if (this.opts.element.data("select2-change-triggered") !== true) {
1106
+ this.initSelection();
1107
+ }
1108
+ }));
1109
+
1110
+ this._sync = this.bind(function () {
1111
+
1112
+ // sync enabled state
1113
+ var disabled = el.prop("disabled");
1114
+ if (disabled === undefined) disabled = false;
1115
+ this.enable(!disabled);
1116
+
1117
+ var readonly = el.prop("readonly");
1118
+ if (readonly === undefined) readonly = false;
1119
+ this.readonly(readonly);
1120
+
1121
+ if (this.container) {
1122
+ syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
1123
+ this.container.addClass(evaluate(this.opts.containerCssClass, this.opts.element));
1124
+ }
1125
+
1126
+ if (this.dropdown) {
1127
+ syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
1128
+ this.dropdown.addClass(evaluate(this.opts.dropdownCssClass, this.opts.element));
1129
+ }
1130
+
1131
+ });
1132
+
1133
+ // IE8-10 (IE9/10 won't fire propertyChange via attachEventListener)
1134
+ if (el.length && el[0].attachEvent) {
1135
+ el.each(function() {
1136
+ this.attachEvent("onpropertychange", self._sync);
1137
+ });
1138
+ }
1139
+
1140
+ // safari, chrome, firefox, IE11
1141
+ observer = window.MutationObserver || window.WebKitMutationObserver|| window.MozMutationObserver;
1142
+ if (observer !== undefined) {
1143
+ if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; }
1144
+ this.propertyObserver = new observer(function (mutations) {
1145
+ $.each(mutations, self._sync);
1146
+ });
1147
+ this.propertyObserver.observe(el.get(0), { attributes:true, subtree:false });
1148
+ }
1149
+ },
1150
+
1151
+ // abstract
1152
+ triggerSelect: function(data) {
1153
+ var evt = $.Event("select2-selecting", { val: this.id(data), object: data, choice: data });
1154
+ this.opts.element.trigger(evt);
1155
+ return !evt.isDefaultPrevented();
1156
+ },
1157
+
1158
+ /**
1159
+ * Triggers the change event on the source element
1160
+ */
1161
+ // abstract
1162
+ triggerChange: function (details) {
1163
+
1164
+ details = details || {};
1165
+ details= $.extend({}, details, { type: "change", val: this.val() });
1166
+ // prevents recursive triggering
1167
+ this.opts.element.data("select2-change-triggered", true);
1168
+ this.opts.element.trigger(details);
1169
+ this.opts.element.data("select2-change-triggered", false);
1170
+
1171
+ // some validation frameworks ignore the change event and listen instead to keyup, click for selects
1172
+ // so here we trigger the click event manually
1173
+ this.opts.element.click();
1174
+
1175
+ // ValidationEngine ignores the change event and listens instead to blur
1176
+ // so here we trigger the blur event manually if so desired
1177
+ if (this.opts.blurOnChange)
1178
+ this.opts.element.blur();
1179
+ },
1180
+
1181
+ //abstract
1182
+ isInterfaceEnabled: function()
1183
+ {
1184
+ return this.enabledInterface === true;
1185
+ },
1186
+
1187
+ // abstract
1188
+ enableInterface: function() {
1189
+ var enabled = this._enabled && !this._readonly,
1190
+ disabled = !enabled;
1191
+
1192
+ if (enabled === this.enabledInterface) return false;
1193
+
1194
+ this.container.toggleClass("select2-container-disabled", disabled);
1195
+ this.close();
1196
+ this.enabledInterface = enabled;
1197
+
1198
+ return true;
1199
+ },
1200
+
1201
+ // abstract
1202
+ enable: function(enabled) {
1203
+ if (enabled === undefined) enabled = true;
1204
+ if (this._enabled === enabled) return;
1205
+ this._enabled = enabled;
1206
+
1207
+ this.opts.element.prop("disabled", !enabled);
1208
+ this.enableInterface();
1209
+ },
1210
+
1211
+ // abstract
1212
+ disable: function() {
1213
+ this.enable(false);
1214
+ },
1215
+
1216
+ // abstract
1217
+ readonly: function(enabled) {
1218
+ if (enabled === undefined) enabled = false;
1219
+ if (this._readonly === enabled) return;
1220
+ this._readonly = enabled;
1221
+
1222
+ this.opts.element.prop("readonly", enabled);
1223
+ this.enableInterface();
1224
+ },
1225
+
1226
+ // abstract
1227
+ opened: function () {
1228
+ return (this.container) ? this.container.hasClass("select2-dropdown-open") : false;
1229
+ },
1230
+
1231
+ // abstract
1232
+ positionDropdown: function() {
1233
+ var $dropdown = this.dropdown,
1234
+ container = this.container,
1235
+ offset = container.offset(),
1236
+ height = container.outerHeight(false),
1237
+ width = container.outerWidth(false),
1238
+ dropHeight = $dropdown.outerHeight(false),
1239
+ $window = $(window),
1240
+ windowWidth = $window.width(),
1241
+ windowHeight = $window.height(),
1242
+ viewPortRight = $window.scrollLeft() + windowWidth,
1243
+ viewportBottom = $window.scrollTop() + windowHeight,
1244
+ dropTop = offset.top + height,
1245
+ dropLeft = offset.left,
1246
+ enoughRoomBelow = dropTop + dropHeight <= viewportBottom,
1247
+ enoughRoomAbove = (offset.top - dropHeight) >= $window.scrollTop(),
1248
+ dropWidth = $dropdown.outerWidth(false),
1249
+ enoughRoomOnRight = function() {
1250
+ return dropLeft + dropWidth <= viewPortRight;
1251
+ },
1252
+ enoughRoomOnLeft = function() {
1253
+ return offset.left + viewPortRight + container.outerWidth(false) > dropWidth;
1254
+ },
1255
+ aboveNow = $dropdown.hasClass("select2-drop-above"),
1256
+ bodyOffset,
1257
+ above,
1258
+ changeDirection,
1259
+ css,
1260
+ resultsListNode;
1261
+
1262
+ // always prefer the current above/below alignment, unless there is not enough room
1263
+ if (aboveNow) {
1264
+ above = true;
1265
+ if (!enoughRoomAbove && enoughRoomBelow) {
1266
+ changeDirection = true;
1267
+ above = false;
1268
+ }
1269
+ } else {
1270
+ above = false;
1271
+ if (!enoughRoomBelow && enoughRoomAbove) {
1272
+ changeDirection = true;
1273
+ above = true;
1274
+ }
1275
+ }
1276
+
1277
+ //if we are changing direction we need to get positions when dropdown is hidden;
1278
+ if (changeDirection) {
1279
+ $dropdown.hide();
1280
+ offset = this.container.offset();
1281
+ height = this.container.outerHeight(false);
1282
+ width = this.container.outerWidth(false);
1283
+ dropHeight = $dropdown.outerHeight(false);
1284
+ viewPortRight = $window.scrollLeft() + windowWidth;
1285
+ viewportBottom = $window.scrollTop() + windowHeight;
1286
+ dropTop = offset.top + height;
1287
+ dropLeft = offset.left;
1288
+ dropWidth = $dropdown.outerWidth(false);
1289
+ $dropdown.show();
1290
+
1291
+ // fix so the cursor does not move to the left within the search-textbox in IE
1292
+ this.focusSearch();
1293
+ }
1294
+
1295
+ if (this.opts.dropdownAutoWidth) {
1296
+ resultsListNode = $('.select2-results', $dropdown)[0];
1297
+ $dropdown.addClass('select2-drop-auto-width');
1298
+ $dropdown.css('width', '');
1299
+ // Add scrollbar width to dropdown if vertical scrollbar is present
1300
+ dropWidth = $dropdown.outerWidth(false) + (resultsListNode.scrollHeight === resultsListNode.clientHeight ? 0 : scrollBarDimensions.width);
1301
+ dropWidth > width ? width = dropWidth : dropWidth = width;
1302
+ dropHeight = $dropdown.outerHeight(false);
1303
+ }
1304
+ else {
1305
+ this.container.removeClass('select2-drop-auto-width');
1306
+ }
1307
+
1308
+ //console.log("below/ droptop:", dropTop, "dropHeight", dropHeight, "sum", (dropTop+dropHeight)+" viewport bottom", viewportBottom, "enough?", enoughRoomBelow);
1309
+ //console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body.scrollTop(), "enough?", enoughRoomAbove);
1310
+
1311
+ // fix positioning when body has an offset and is not position: static
1312
+ if (this.body.css('position') !== 'static') {
1313
+ bodyOffset = this.body.offset();
1314
+ dropTop -= bodyOffset.top;
1315
+ dropLeft -= bodyOffset.left;
1316
+ }
1317
+
1318
+ if (!enoughRoomOnRight() && enoughRoomOnLeft()) {
1319
+ dropLeft = offset.left + this.container.outerWidth(false) - dropWidth;
1320
+ }
1321
+
1322
+ css = {
1323
+ left: dropLeft,
1324
+ width: width
1325
+ };
1326
+
1327
+ if (above) {
1328
+ css.top = offset.top - dropHeight;
1329
+ css.bottom = 'auto';
1330
+ this.container.addClass("select2-drop-above");
1331
+ $dropdown.addClass("select2-drop-above");
1332
+ }
1333
+ else {
1334
+ css.top = dropTop;
1335
+ css.bottom = 'auto';
1336
+ this.container.removeClass("select2-drop-above");
1337
+ $dropdown.removeClass("select2-drop-above");
1338
+ }
1339
+ css = $.extend(css, evaluate(this.opts.dropdownCss, this.opts.element));
1340
+
1341
+ $dropdown.css(css);
1342
+ },
1343
+
1344
+ // abstract
1345
+ shouldOpen: function() {
1346
+ var event;
1347
+
1348
+ if (this.opened()) return false;
1349
+
1350
+ if (this._enabled === false || this._readonly === true) return false;
1351
+
1352
+ event = $.Event("select2-opening");
1353
+ this.opts.element.trigger(event);
1354
+ return !event.isDefaultPrevented();
1355
+ },
1356
+
1357
+ // abstract
1358
+ clearDropdownAlignmentPreference: function() {
1359
+ // clear the classes used to figure out the preference of where the dropdown should be opened
1360
+ this.container.removeClass("select2-drop-above");
1361
+ this.dropdown.removeClass("select2-drop-above");
1362
+ },
1363
+
1364
+ /**
1365
+ * Opens the dropdown
1366
+ *
1367
+ * @return {Boolean} whether or not dropdown was opened. This method will return false if, for example,
1368
+ * the dropdown is already open, or if the 'open' event listener on the element called preventDefault().
1369
+ */
1370
+ // abstract
1371
+ open: function () {
1372
+
1373
+ if (!this.shouldOpen()) return false;
1374
+
1375
+ this.opening();
1376
+
1377
+ // Only bind the document mousemove when the dropdown is visible
1378
+ $document.on("mousemove.select2Event", function (e) {
1379
+ lastMousePosition.x = e.pageX;
1380
+ lastMousePosition.y = e.pageY;
1381
+ });
1382
+
1383
+ return true;
1384
+ },
1385
+
1386
+ /**
1387
+ * Performs the opening of the dropdown
1388
+ */
1389
+ // abstract
1390
+ opening: function() {
1391
+ var cid = this.containerEventName,
1392
+ scroll = "scroll." + cid,
1393
+ resize = "resize."+cid,
1394
+ orient = "orientationchange."+cid,
1395
+ mask;
1396
+
1397
+ this.container.addClass("select2-dropdown-open").addClass("select2-container-active");
1398
+
1399
+ this.clearDropdownAlignmentPreference();
1400
+
1401
+ if(this.dropdown[0] !== this.body.children().last()[0]) {
1402
+ this.dropdown.detach().appendTo(this.body);
1403
+ }
1404
+
1405
+ // create the dropdown mask if doesn't already exist
1406
+ mask = $("#select2-drop-mask");
1407
+ if (mask.length === 0) {
1408
+ mask = $(document.createElement("div"));
1409
+ mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask");
1410
+ mask.hide();
1411
+ mask.appendTo(this.body);
1412
+ mask.on("mousedown touchstart click", function (e) {
1413
+ // Prevent IE from generating a click event on the body
1414
+ reinsertElement(mask);
1415
+
1416
+ var dropdown = $("#select2-drop"), self;
1417
+ if (dropdown.length > 0) {
1418
+ self=dropdown.data("select2");
1419
+ if (self.opts.selectOnBlur) {
1420
+ self.selectHighlighted({noFocus: true});
1421
+ }
1422
+ self.close();
1423
+ e.preventDefault();
1424
+ e.stopPropagation();
1425
+ }
1426
+ });
1427
+ }
1428
+
1429
+ // ensure the mask is always right before the dropdown
1430
+ if (this.dropdown.prev()[0] !== mask[0]) {
1431
+ this.dropdown.before(mask);
1432
+ }
1433
+
1434
+ // move the global id to the correct dropdown
1435
+ $("#select2-drop").removeAttr("id");
1436
+ this.dropdown.attr("id", "select2-drop");
1437
+
1438
+ // show the elements
1439
+ mask.show();
1440
+
1441
+ this.positionDropdown();
1442
+ this.dropdown.show();
1443
+ this.positionDropdown();
1444
+
1445
+ this.dropdown.addClass("select2-drop-active");
1446
+
1447
+ // attach listeners to events that can change the position of the container and thus require
1448
+ // the position of the dropdown to be updated as well so it does not come unglued from the container
1449
+ var that = this;
1450
+ this.container.parents().add(window).each(function () {
1451
+ $(this).on(resize+" "+scroll+" "+orient, function (e) {
1452
+ if (that.opened()) that.positionDropdown();
1453
+ });
1454
+ });
1455
+
1456
+
1457
+ },
1458
+
1459
+ // abstract
1460
+ close: function () {
1461
+ if (!this.opened()) return;
1462
+
1463
+ var cid = this.containerEventName,
1464
+ scroll = "scroll." + cid,
1465
+ resize = "resize."+cid,
1466
+ orient = "orientationchange."+cid;
1467
+
1468
+ // unbind event listeners
1469
+ this.container.parents().add(window).each(function () { $(this).off(scroll).off(resize).off(orient); });
1470
+
1471
+ this.clearDropdownAlignmentPreference();
1472
+
1473
+ $("#select2-drop-mask").hide();
1474
+ this.dropdown.removeAttr("id"); // only the active dropdown has the select2-drop id
1475
+ this.dropdown.hide();
1476
+ this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active");
1477
+ this.results.empty();
1478
+
1479
+ // Now that the dropdown is closed, unbind the global document mousemove event
1480
+ $document.off("mousemove.select2Event");
1481
+
1482
+ this.clearSearch();
1483
+ this.search.removeClass("select2-active");
1484
+ this.opts.element.trigger($.Event("select2-close"));
1485
+ },
1486
+
1487
+ /**
1488
+ * Opens control, sets input value, and updates results.
1489
+ */
1490
+ // abstract
1491
+ externalSearch: function (term) {
1492
+ this.open();
1493
+ this.search.val(term);
1494
+ this.updateResults(false);
1495
+ },
1496
+
1497
+ // abstract
1498
+ clearSearch: function () {
1499
+
1500
+ },
1501
+
1502
+ //abstract
1503
+ getMaximumSelectionSize: function() {
1504
+ return evaluate(this.opts.maximumSelectionSize, this.opts.element);
1505
+ },
1506
+
1507
+ // abstract
1508
+ ensureHighlightVisible: function () {
1509
+ var results = this.results, children, index, child, hb, rb, y, more, topOffset;
1510
+
1511
+ index = this.highlight();
1512
+
1513
+ if (index < 0) return;
1514
+
1515
+ if (index == 0) {
1516
+
1517
+ // if the first element is highlighted scroll all the way to the top,
1518
+ // that way any unselectable headers above it will also be scrolled
1519
+ // into view
1520
+
1521
+ results.scrollTop(0);
1522
+ return;
1523
+ }
1524
+
1525
+ children = this.findHighlightableChoices().find('.select2-result-label');
1526
+
1527
+ child = $(children[index]);
1528
+
1529
+ topOffset = (child.offset() || {}).top || 0;
1530
+
1531
+ hb = topOffset + child.outerHeight(true);
1532
+
1533
+ // if this is the last child lets also make sure select2-more-results is visible
1534
+ if (index === children.length - 1) {
1535
+ more = results.find("li.select2-more-results");
1536
+ if (more.length > 0) {
1537
+ hb = more.offset().top + more.outerHeight(true);
1538
+ }
1539
+ }
1540
+
1541
+ rb = results.offset().top + results.outerHeight(false);
1542
+ if (hb > rb) {
1543
+ results.scrollTop(results.scrollTop() + (hb - rb));
1544
+ }
1545
+ y = topOffset - results.offset().top;
1546
+
1547
+ // make sure the top of the element is visible
1548
+ if (y < 0 && child.css('display') != 'none' ) {
1549
+ results.scrollTop(results.scrollTop() + y); // y is negative
1550
+ }
1551
+ },
1552
+
1553
+ // abstract
1554
+ findHighlightableChoices: function() {
1555
+ return this.results.find(".select2-result-selectable:not(.select2-disabled):not(.select2-selected)");
1556
+ },
1557
+
1558
+ // abstract
1559
+ moveHighlight: function (delta) {
1560
+ var choices = this.findHighlightableChoices(),
1561
+ index = this.highlight();
1562
+
1563
+ while (index > -1 && index < choices.length) {
1564
+ index += delta;
1565
+ var choice = $(choices[index]);
1566
+ if (choice.hasClass("select2-result-selectable") && !choice.hasClass("select2-disabled") && !choice.hasClass("select2-selected")) {
1567
+ this.highlight(index);
1568
+ break;
1569
+ }
1570
+ }
1571
+ },
1572
+
1573
+ // abstract
1574
+ highlight: function (index) {
1575
+ var choices = this.findHighlightableChoices(),
1576
+ choice,
1577
+ data;
1578
+
1579
+ if (arguments.length === 0) {
1580
+ return indexOf(choices.filter(".select2-highlighted")[0], choices.get());
1581
+ }
1582
+
1583
+ if (index >= choices.length) index = choices.length - 1;
1584
+ if (index < 0) index = 0;
1585
+
1586
+ this.removeHighlight();
1587
+
1588
+ choice = $(choices[index]);
1589
+ choice.addClass("select2-highlighted");
1590
+
1591
+ // ensure assistive technology can determine the active choice
1592
+ this.search.attr("aria-activedescendant", choice.find(".select2-result-label").attr("id"));
1593
+
1594
+ this.ensureHighlightVisible();
1595
+
1596
+ this.liveRegion.text(choice.text());
1597
+
1598
+ data = choice.data("select2-data");
1599
+ if (data) {
1600
+ this.opts.element.trigger({ type: "select2-highlight", val: this.id(data), choice: data });
1601
+ }
1602
+ },
1603
+
1604
+ removeHighlight: function() {
1605
+ this.results.find(".select2-highlighted").removeClass("select2-highlighted");
1606
+ },
1607
+
1608
+ touchMoved: function() {
1609
+ this._touchMoved = true;
1610
+ },
1611
+
1612
+ clearTouchMoved: function() {
1613
+ this._touchMoved = false;
1614
+ },
1615
+
1616
+ // abstract
1617
+ countSelectableResults: function() {
1618
+ return this.findHighlightableChoices().length;
1619
+ },
1620
+
1621
+ // abstract
1622
+ highlightUnderEvent: function (event) {
1623
+ var el = $(event.target).closest(".select2-result-selectable");
1624
+ if (el.length > 0 && !el.is(".select2-highlighted")) {
1625
+ var choices = this.findHighlightableChoices();
1626
+ this.highlight(choices.index(el));
1627
+ } else if (el.length == 0) {
1628
+ // if we are over an unselectable item remove all highlights
1629
+ this.removeHighlight();
1630
+ }
1631
+ },
1632
+
1633
+ // abstract
1634
+ loadMoreIfNeeded: function () {
1635
+ var results = this.results,
1636
+ more = results.find("li.select2-more-results"),
1637
+ below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible
1638
+ page = this.resultsPage + 1,
1639
+ self=this,
1640
+ term=this.search.val(),
1641
+ context=this.context;
1642
+
1643
+ if (more.length === 0) return;
1644
+ below = more.offset().top - results.offset().top - results.height();
1645
+
1646
+ if (below <= this.opts.loadMorePadding) {
1647
+ more.addClass("select2-active");
1648
+ this.opts.query({
1649
+ element: this.opts.element,
1650
+ term: term,
1651
+ page: page,
1652
+ context: context,
1653
+ matcher: this.opts.matcher,
1654
+ callback: this.bind(function (data) {
1655
+
1656
+ // ignore a response if the select2 has been closed before it was received
1657
+ if (!self.opened()) return;
1658
+
1659
+
1660
+ self.opts.populateResults.call(this, results, data.results, {term: term, page: page, context:context});
1661
+ self.postprocessResults(data, false, false);
1662
+
1663
+ if (data.more===true) {
1664
+ more.detach().appendTo(results).html(self.opts.escapeMarkup(evaluate(self.opts.formatLoadMore, self.opts.element, page+1)));
1665
+ window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
1666
+ } else {
1667
+ more.remove();
1668
+ }
1669
+ self.positionDropdown();
1670
+ self.resultsPage = page;
1671
+ self.context = data.context;
1672
+ this.opts.element.trigger({ type: "select2-loaded", items: data });
1673
+ })});
1674
+ }
1675
+ },
1676
+
1677
+ /**
1678
+ * Default tokenizer function which does nothing
1679
+ */
1680
+ tokenize: function() {
1681
+
1682
+ },
1683
+
1684
+ /**
1685
+ * @param initial whether or not this is the call to this method right after the dropdown has been opened
1686
+ */
1687
+ // abstract
1688
+ updateResults: function (initial) {
1689
+ var search = this.search,
1690
+ results = this.results,
1691
+ opts = this.opts,
1692
+ data,
1693
+ self = this,
1694
+ input,
1695
+ term = search.val(),
1696
+ lastTerm = $.data(this.container, "select2-last-term"),
1697
+ // sequence number used to drop out-of-order responses
1698
+ queryNumber;
1699
+
1700
+ // prevent duplicate queries against the same term
1701
+ if (initial !== true && lastTerm && equal(term, lastTerm)) return;
1702
+
1703
+ $.data(this.container, "select2-last-term", term);
1704
+
1705
+ // if the search is currently hidden we do not alter the results
1706
+ if (initial !== true && (this.showSearchInput === false || !this.opened())) {
1707
+ return;
1708
+ }
1709
+
1710
+ function postRender() {
1711
+ search.removeClass("select2-active");
1712
+ self.positionDropdown();
1713
+ if (results.find('.select2-no-results,.select2-selection-limit,.select2-searching').length) {
1714
+ self.liveRegion.text(results.text());
1715
+ }
1716
+ else {
1717
+ self.liveRegion.text(self.opts.formatMatches(results.find('.select2-result-selectable:not(".select2-selected")').length));
1718
+ }
1719
+ }
1720
+
1721
+ function render(html) {
1722
+ results.html(html);
1723
+ postRender();
1724
+ }
1725
+
1726
+ queryNumber = ++this.queryCount;
1727
+
1728
+ var maxSelSize = this.getMaximumSelectionSize();
1729
+ if (maxSelSize >=1) {
1730
+ data = this.data();
1731
+ if ($.isArray(data) && data.length >= maxSelSize && checkFormatter(opts.formatSelectionTooBig, "formatSelectionTooBig")) {
1732
+ render("<li class='select2-selection-limit'>" + evaluate(opts.formatSelectionTooBig, opts.element, maxSelSize) + "</li>");
1733
+ return;
1734
+ }
1735
+ }
1736
+
1737
+ if (search.val().length < opts.minimumInputLength) {
1738
+ if (checkFormatter(opts.formatInputTooShort, "formatInputTooShort")) {
1739
+ render("<li class='select2-no-results'>" + evaluate(opts.formatInputTooShort, opts.element, search.val(), opts.minimumInputLength) + "</li>");
1740
+ } else {
1741
+ render("");
1742
+ }
1743
+ if (initial && this.showSearch) this.showSearch(true);
1744
+ return;
1745
+ }
1746
+
1747
+ if (opts.maximumInputLength && search.val().length > opts.maximumInputLength) {
1748
+ if (checkFormatter(opts.formatInputTooLong, "formatInputTooLong")) {
1749
+ render("<li class='select2-no-results'>" + evaluate(opts.formatInputTooLong, opts.element, search.val(), opts.maximumInputLength) + "</li>");
1750
+ } else {
1751
+ render("");
1752
+ }
1753
+ return;
1754
+ }
1755
+
1756
+ if (opts.formatSearching && this.findHighlightableChoices().length === 0) {
1757
+ render("<li class='select2-searching'>" + evaluate(opts.formatSearching, opts.element) + "</li>");
1758
+ }
1759
+
1760
+ search.addClass("select2-active");
1761
+
1762
+ this.removeHighlight();
1763
+
1764
+ // give the tokenizer a chance to pre-process the input
1765
+ input = this.tokenize();
1766
+ if (input != undefined && input != null) {
1767
+ search.val(input);
1768
+ }
1769
+
1770
+ this.resultsPage = 1;
1771
+
1772
+ opts.query({
1773
+ element: opts.element,
1774
+ term: search.val(),
1775
+ page: this.resultsPage,
1776
+ context: null,
1777
+ matcher: opts.matcher,
1778
+ callback: this.bind(function (data) {
1779
+ var def; // default choice
1780
+
1781
+ // ignore old responses
1782
+ if (queryNumber != this.queryCount) {
1783
+ return;
1784
+ }
1785
+
1786
+ // ignore a response if the select2 has been closed before it was received
1787
+ if (!this.opened()) {
1788
+ this.search.removeClass("select2-active");
1789
+ return;
1790
+ }
1791
+
1792
+ // handle ajax error
1793
+ if(data.hasError !== undefined && checkFormatter(opts.formatAjaxError, "formatAjaxError")) {
1794
+ render("<li class='select2-ajax-error'>" + evaluate(opts.formatAjaxError, opts.element, data.jqXHR, data.textStatus, data.errorThrown) + "</li>");
1795
+ return;
1796
+ }
1797
+
1798
+ // save context, if any
1799
+ this.context = (data.context===undefined) ? null : data.context;
1800
+ // create a default choice and prepend it to the list
1801
+ if (this.opts.createSearchChoice && search.val() !== "") {
1802
+ def = this.opts.createSearchChoice.call(self, search.val(), data.results);
1803
+ if (def !== undefined && def !== null && self.id(def) !== undefined && self.id(def) !== null) {
1804
+ if ($(data.results).filter(
1805
+ function () {
1806
+ return equal(self.id(this), self.id(def));
1807
+ }).length === 0) {
1808
+ this.opts.createSearchChoicePosition(data.results, def);
1809
+ }
1810
+ }
1811
+ }
1812
+
1813
+ if (data.results.length === 0 && checkFormatter(opts.formatNoMatches, "formatNoMatches")) {
1814
+ render("<li class='select2-no-results'>" + evaluate(opts.formatNoMatches, opts.element, search.val()) + "</li>");
1815
+ return;
1816
+ }
1817
+
1818
+ results.empty();
1819
+ self.opts.populateResults.call(this, results, data.results, {term: search.val(), page: this.resultsPage, context:null});
1820
+
1821
+ if (data.more === true && checkFormatter(opts.formatLoadMore, "formatLoadMore")) {
1822
+ results.append("<li class='select2-more-results'>" + opts.escapeMarkup(evaluate(opts.formatLoadMore, opts.element, this.resultsPage)) + "</li>");
1823
+ window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
1824
+ }
1825
+
1826
+ this.postprocessResults(data, initial);
1827
+
1828
+ postRender();
1829
+
1830
+ this.opts.element.trigger({ type: "select2-loaded", items: data });
1831
+ })});
1832
+ },
1833
+
1834
+ // abstract
1835
+ cancel: function () {
1836
+ this.close();
1837
+ },
1838
+
1839
+ // abstract
1840
+ blur: function () {
1841
+ // if selectOnBlur == true, select the currently highlighted option
1842
+ if (this.opts.selectOnBlur)
1843
+ this.selectHighlighted({noFocus: true});
1844
+
1845
+ this.close();
1846
+ this.container.removeClass("select2-container-active");
1847
+ // synonymous to .is(':focus'), which is available in jquery >= 1.6
1848
+ if (this.search[0] === document.activeElement) { this.search.blur(); }
1849
+ this.clearSearch();
1850
+ this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
1851
+ },
1852
+
1853
+ // abstract
1854
+ focusSearch: function () {
1855
+ focus(this.search);
1856
+ },
1857
+
1858
+ // abstract
1859
+ selectHighlighted: function (options) {
1860
+ if (this._touchMoved) {
1861
+ this.clearTouchMoved();
1862
+ return;
1863
+ }
1864
+ var index=this.highlight(),
1865
+ highlighted=this.results.find(".select2-highlighted"),
1866
+ data = highlighted.closest('.select2-result').data("select2-data");
1867
+
1868
+ if (data) {
1869
+ this.highlight(index);
1870
+ this.onSelect(data, options);
1871
+ } else if (options && options.noFocus) {
1872
+ this.close();
1873
+ }
1874
+ },
1875
+
1876
+ // abstract
1877
+ getPlaceholder: function () {
1878
+ var placeholderOption;
1879
+ return this.opts.element.attr("placeholder") ||
1880
+ this.opts.element.attr("data-placeholder") || // jquery 1.4 compat
1881
+ this.opts.element.data("placeholder") ||
1882
+ this.opts.placeholder ||
1883
+ ((placeholderOption = this.getPlaceholderOption()) !== undefined ? placeholderOption.text() : undefined);
1884
+ },
1885
+
1886
+ // abstract
1887
+ getPlaceholderOption: function() {
1888
+ if (this.select) {
1889
+ var firstOption = this.select.children('option').first();
1890
+ if (this.opts.placeholderOption !== undefined ) {
1891
+ //Determine the placeholder option based on the specified placeholderOption setting
1892
+ return (this.opts.placeholderOption === "first" && firstOption) ||
1893
+ (typeof this.opts.placeholderOption === "function" && this.opts.placeholderOption(this.select));
1894
+ } else if ($.trim(firstOption.text()) === "" && firstOption.val() === "") {
1895
+ //No explicit placeholder option specified, use the first if it's blank
1896
+ return firstOption;
1897
+ }
1898
+ }
1899
+ },
1900
+
1901
+ /**
1902
+ * Get the desired width for the container element. This is
1903
+ * derived first from option `width` passed to select2, then
1904
+ * the inline 'style' on the original element, and finally
1905
+ * falls back to the jQuery calculated element width.
1906
+ */
1907
+ // abstract
1908
+ initContainerWidth: function () {
1909
+ function resolveContainerWidth() {
1910
+ var style, attrs, matches, i, l, attr;
1911
+
1912
+ if (this.opts.width === "off") {
1913
+ return null;
1914
+ } else if (this.opts.width === "element"){
1915
+ return this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px';
1916
+ } else if (this.opts.width === "copy" || this.opts.width === "resolve") {
1917
+ // check if there is inline style on the element that contains width
1918
+ style = this.opts.element.attr('style');
1919
+ if (style !== undefined) {
1920
+ attrs = style.split(';');
1921
+ for (i = 0, l = attrs.length; i < l; i = i + 1) {
1922
+ attr = attrs[i].replace(/\s/g, '');
1923
+ matches = attr.match(/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i);
1924
+ if (matches !== null && matches.length >= 1)
1925
+ return matches[1];
1926
+ }
1927
+ }
1928
+
1929
+ if (this.opts.width === "resolve") {
1930
+ // next check if css('width') can resolve a width that is percent based, this is sometimes possible
1931
+ // when attached to input type=hidden or elements hidden via css
1932
+ style = this.opts.element.css('width');
1933
+ if (style.indexOf("%") > 0) return style;
1934
+
1935
+ // finally, fallback on the calculated width of the element
1936
+ return (this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px');
1937
+ }
1938
+
1939
+ return null;
1940
+ } else if ($.isFunction(this.opts.width)) {
1941
+ return this.opts.width();
1942
+ } else {
1943
+ return this.opts.width;
1944
+ }
1945
+ };
1946
+
1947
+ var width = resolveContainerWidth.call(this);
1948
+ if (width !== null) {
1949
+ this.container.css("width", width);
1950
+ }
1951
+ }
1952
+ });
1953
+
1954
+ SingleSelect2 = clazz(AbstractSelect2, {
1955
+
1956
+ // single
1957
+
1958
+ createContainer: function () {
1959
+ var container = $(document.createElement("div")).attr({
1960
+ "class": "select2-container"
1961
+ }).html([
1962
+ "<a href='javascript:void(0)' class='select2-choice' tabindex='-1'>",
1963
+ " <span class='select2-chosen'>&#160;</span><abbr class='select2-search-choice-close'></abbr>",
1964
+ " <span class='select2-arrow' role='presentation'><b role='presentation'></b></span>",
1965
+ "</a>",
1966
+ "<label for='' class='select2-offscreen'></label>",
1967
+ "<input class='select2-focusser select2-offscreen' type='text' aria-haspopup='true' role='button' />",
1968
+ "<div class='select2-drop select2-display-none'>",
1969
+ " <div class='select2-search'>",
1970
+ " <label for='' class='select2-offscreen'></label>",
1971
+ " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input' role='combobox' aria-expanded='true'",
1972
+ " aria-autocomplete='list' />",
1973
+ " </div>",
1974
+ " <ul class='select2-results' role='listbox'>",
1975
+ " </ul>",
1976
+ "</div>"].join(""));
1977
+ return container;
1978
+ },
1979
+
1980
+ // single
1981
+ enableInterface: function() {
1982
+ if (this.parent.enableInterface.apply(this, arguments)) {
1983
+ this.focusser.prop("disabled", !this.isInterfaceEnabled());
1984
+ }
1985
+ },
1986
+
1987
+ // single
1988
+ opening: function () {
1989
+ var el, range, len;
1990
+
1991
+ if (this.opts.minimumResultsForSearch >= 0) {
1992
+ this.showSearch(true);
1993
+ }
1994
+
1995
+ this.parent.opening.apply(this, arguments);
1996
+
1997
+ if (this.showSearchInput !== false) {
1998
+ // IE appends focusser.val() at the end of field :/ so we manually insert it at the beginning using a range
1999
+ // all other browsers handle this just fine
2000
+
2001
+ this.search.val(this.focusser.val());
2002
+ }
2003
+ if (this.opts.shouldFocusInput(this)) {
2004
+ this.search.focus();
2005
+ // move the cursor to the end after focussing, otherwise it will be at the beginning and
2006
+ // new text will appear *before* focusser.val()
2007
+ el = this.search.get(0);
2008
+ if (el.createTextRange) {
2009
+ range = el.createTextRange();
2010
+ range.collapse(false);
2011
+ range.select();
2012
+ } else if (el.setSelectionRange) {
2013
+ len = this.search.val().length;
2014
+ el.setSelectionRange(len, len);
2015
+ }
2016
+ }
2017
+
2018
+ // initializes search's value with nextSearchTerm (if defined by user)
2019
+ // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter
2020
+ if(this.search.val() === "") {
2021
+ if(this.nextSearchTerm != undefined){
2022
+ this.search.val(this.nextSearchTerm);
2023
+ this.search.select();
2024
+ }
2025
+ }
2026
+
2027
+ this.focusser.prop("disabled", true).val("");
2028
+ this.updateResults(true);
2029
+ this.opts.element.trigger($.Event("select2-open"));
2030
+ },
2031
+
2032
+ // single
2033
+ close: function () {
2034
+ if (!this.opened()) return;
2035
+ this.parent.close.apply(this, arguments);
2036
+
2037
+ this.focusser.prop("disabled", false);
2038
+
2039
+ if (this.opts.shouldFocusInput(this)) {
2040
+ this.focusser.focus();
2041
+ }
2042
+ },
2043
+
2044
+ // single
2045
+ focus: function () {
2046
+ if (this.opened()) {
2047
+ this.close();
2048
+ } else {
2049
+ this.focusser.prop("disabled", false);
2050
+ if (this.opts.shouldFocusInput(this)) {
2051
+ this.focusser.focus();
2052
+ }
2053
+ }
2054
+ },
2055
+
2056
+ // single
2057
+ isFocused: function () {
2058
+ return this.container.hasClass("select2-container-active");
2059
+ },
2060
+
2061
+ // single
2062
+ cancel: function () {
2063
+ this.parent.cancel.apply(this, arguments);
2064
+ this.focusser.prop("disabled", false);
2065
+
2066
+ if (this.opts.shouldFocusInput(this)) {
2067
+ this.focusser.focus();
2068
+ }
2069
+ },
2070
+
2071
+ // single
2072
+ destroy: function() {
2073
+ $("label[for='" + this.focusser.attr('id') + "']")
2074
+ .attr('for', this.opts.element.attr("id"));
2075
+ this.parent.destroy.apply(this, arguments);
2076
+
2077
+ cleanupJQueryElements.call(this,
2078
+ "selection",
2079
+ "focusser"
2080
+ );
2081
+ },
2082
+
2083
+ // single
2084
+ initContainer: function () {
2085
+
2086
+ var selection,
2087
+ container = this.container,
2088
+ dropdown = this.dropdown,
2089
+ idSuffix = nextUid(),
2090
+ elementLabel;
2091
+
2092
+ if (this.opts.minimumResultsForSearch < 0) {
2093
+ this.showSearch(false);
2094
+ } else {
2095
+ this.showSearch(true);
2096
+ }
2097
+
2098
+ this.selection = selection = container.find(".select2-choice");
2099
+
2100
+ this.focusser = container.find(".select2-focusser");
2101
+
2102
+ // add aria associations
2103
+ selection.find(".select2-chosen").attr("id", "select2-chosen-"+idSuffix);
2104
+ this.focusser.attr("aria-labelledby", "select2-chosen-"+idSuffix);
2105
+ this.results.attr("id", "select2-results-"+idSuffix);
2106
+ this.search.attr("aria-owns", "select2-results-"+idSuffix);
2107
+
2108
+ // rewrite labels from original element to focusser
2109
+ this.focusser.attr("id", "s2id_autogen"+idSuffix);
2110
+
2111
+ elementLabel = $("label[for='" + this.opts.element.attr("id") + "']");
2112
+ this.opts.element.focus(this.bind(function () { this.focus(); }));
2113
+
2114
+ this.focusser.prev()
2115
+ .text(elementLabel.text())
2116
+ .attr('for', this.focusser.attr('id'));
2117
+
2118
+ // Ensure the original element retains an accessible name
2119
+ var originalTitle = this.opts.element.attr("title");
2120
+ this.opts.element.attr("title", (originalTitle || elementLabel.text()));
2121
+
2122
+ this.focusser.attr("tabindex", this.elementTabIndex);
2123
+
2124
+ // write label for search field using the label from the focusser element
2125
+ this.search.attr("id", this.focusser.attr('id') + '_search');
2126
+
2127
+ this.search.prev()
2128
+ .text($("label[for='" + this.focusser.attr('id') + "']").text())
2129
+ .attr('for', this.search.attr('id'));
2130
+
2131
+ this.search.on("keydown", this.bind(function (e) {
2132
+ if (!this.isInterfaceEnabled()) return;
2133
+
2134
+ // filter 229 keyCodes (input method editor is processing key input)
2135
+ if (229 == e.keyCode) return;
2136
+
2137
+ if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) {
2138
+ // prevent the page from scrolling
2139
+ killEvent(e);
2140
+ return;
2141
+ }
2142
+
2143
+ switch (e.which) {
2144
+ case KEY.UP:
2145
+ case KEY.DOWN:
2146
+ this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
2147
+ killEvent(e);
2148
+ return;
2149
+ case KEY.ENTER:
2150
+ this.selectHighlighted();
2151
+ killEvent(e);
2152
+ return;
2153
+ case KEY.TAB:
2154
+ this.selectHighlighted({noFocus: true});
2155
+ return;
2156
+ case KEY.ESC:
2157
+ this.cancel(e);
2158
+ killEvent(e);
2159
+ return;
2160
+ }
2161
+ }));
2162
+
2163
+ this.search.on("blur", this.bind(function(e) {
2164
+ // a workaround for chrome to keep the search field focussed when the scroll bar is used to scroll the dropdown.
2165
+ // without this the search field loses focus which is annoying
2166
+ if (document.activeElement === this.body.get(0)) {
2167
+ window.setTimeout(this.bind(function() {
2168
+ if (this.opened()) {
2169
+ this.search.focus();
2170
+ }
2171
+ }), 0);
2172
+ }
2173
+ }));
2174
+
2175
+ this.focusser.on("keydown", this.bind(function (e) {
2176
+ if (!this.isInterfaceEnabled()) return;
2177
+
2178
+ if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) {
2179
+ return;
2180
+ }
2181
+
2182
+ if (this.opts.openOnEnter === false && e.which === KEY.ENTER) {
2183
+ killEvent(e);
2184
+ return;
2185
+ }
2186
+
2187
+ if (e.which == KEY.DOWN || e.which == KEY.UP
2188
+ || (e.which == KEY.ENTER && this.opts.openOnEnter)) {
2189
+
2190
+ if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) return;
2191
+
2192
+ this.open();
2193
+ killEvent(e);
2194
+ return;
2195
+ }
2196
+
2197
+ if (e.which == KEY.DELETE || e.which == KEY.BACKSPACE) {
2198
+ if (this.opts.allowClear) {
2199
+ this.clear();
2200
+ }
2201
+ killEvent(e);
2202
+ return;
2203
+ }
2204
+ }));
2205
+
2206
+
2207
+ installKeyUpChangeEvent(this.focusser);
2208
+ this.focusser.on("keyup-change input", this.bind(function(e) {
2209
+ if (this.opts.minimumResultsForSearch >= 0) {
2210
+ e.stopPropagation();
2211
+ if (this.opened()) return;
2212
+ this.open();
2213
+ }
2214
+ }));
2215
+
2216
+ selection.on("mousedown touchstart", "abbr", this.bind(function (e) {
2217
+ if (!this.isInterfaceEnabled()) {
2218
+ return;
2219
+ }
2220
+
2221
+ this.clear();
2222
+ killEventImmediately(e);
2223
+ this.close();
2224
+
2225
+ if (this.selection) {
2226
+ this.selection.focus();
2227
+ }
2228
+ }));
2229
+
2230
+ selection.on("mousedown touchstart", this.bind(function (e) {
2231
+ // Prevent IE from generating a click event on the body
2232
+ reinsertElement(selection);
2233
+
2234
+ if (!this.container.hasClass("select2-container-active")) {
2235
+ this.opts.element.trigger($.Event("select2-focus"));
2236
+ }
2237
+
2238
+ if (this.opened()) {
2239
+ this.close();
2240
+ } else if (this.isInterfaceEnabled()) {
2241
+ this.open();
2242
+ }
2243
+
2244
+ killEvent(e);
2245
+ }));
2246
+
2247
+ dropdown.on("mousedown touchstart", this.bind(function() {
2248
+ if (this.opts.shouldFocusInput(this)) {
2249
+ this.search.focus();
2250
+ }
2251
+ }));
2252
+
2253
+ selection.on("focus", this.bind(function(e) {
2254
+ killEvent(e);
2255
+ }));
2256
+
2257
+ this.focusser.on("focus", this.bind(function(){
2258
+ if (!this.container.hasClass("select2-container-active")) {
2259
+ this.opts.element.trigger($.Event("select2-focus"));
2260
+ }
2261
+ this.container.addClass("select2-container-active");
2262
+ })).on("blur", this.bind(function() {
2263
+ if (!this.opened()) {
2264
+ this.container.removeClass("select2-container-active");
2265
+ this.opts.element.trigger($.Event("select2-blur"));
2266
+ }
2267
+ }));
2268
+ this.search.on("focus", this.bind(function(){
2269
+ if (!this.container.hasClass("select2-container-active")) {
2270
+ this.opts.element.trigger($.Event("select2-focus"));
2271
+ }
2272
+ this.container.addClass("select2-container-active");
2273
+ }));
2274
+
2275
+ this.initContainerWidth();
2276
+ this.opts.element.hide();
2277
+ this.setPlaceholder();
2278
+
2279
+ },
2280
+
2281
+ // single
2282
+ clear: function(triggerChange) {
2283
+ var data=this.selection.data("select2-data");
2284
+ if (data) { // guard against queued quick consecutive clicks
2285
+ var evt = $.Event("select2-clearing");
2286
+ this.opts.element.trigger(evt);
2287
+ if (evt.isDefaultPrevented()) {
2288
+ return;
2289
+ }
2290
+ var placeholderOption = this.getPlaceholderOption();
2291
+ this.opts.element.val(placeholderOption ? placeholderOption.val() : "");
2292
+ this.selection.find(".select2-chosen").empty();
2293
+ this.selection.removeData("select2-data");
2294
+ this.setPlaceholder();
2295
+
2296
+ if (triggerChange !== false){
2297
+ this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data });
2298
+ this.triggerChange({removed:data});
2299
+ }
2300
+ }
2301
+ },
2302
+
2303
+ /**
2304
+ * Sets selection based on source element's value
2305
+ */
2306
+ // single
2307
+ initSelection: function () {
2308
+ var selected;
2309
+ if (this.isPlaceholderOptionSelected()) {
2310
+ this.updateSelection(null);
2311
+ this.close();
2312
+ this.setPlaceholder();
2313
+ } else {
2314
+ var self = this;
2315
+ this.opts.initSelection.call(null, this.opts.element, function(selected){
2316
+ if (selected !== undefined && selected !== null) {
2317
+ self.updateSelection(selected);
2318
+ self.close();
2319
+ self.setPlaceholder();
2320
+ self.nextSearchTerm = self.opts.nextSearchTerm(selected, self.search.val());
2321
+ }
2322
+ });
2323
+ }
2324
+ },
2325
+
2326
+ isPlaceholderOptionSelected: function() {
2327
+ var placeholderOption;
2328
+ if (this.getPlaceholder() === undefined) return false; // no placeholder specified so no option should be considered
2329
+ return ((placeholderOption = this.getPlaceholderOption()) !== undefined && placeholderOption.prop("selected"))
2330
+ || (this.opts.element.val() === "")
2331
+ || (this.opts.element.val() === undefined)
2332
+ || (this.opts.element.val() === null);
2333
+ },
2334
+
2335
+ // single
2336
+ prepareOpts: function () {
2337
+ var opts = this.parent.prepareOpts.apply(this, arguments),
2338
+ self=this;
2339
+
2340
+ if (opts.element.get(0).tagName.toLowerCase() === "select") {
2341
+ // install the selection initializer
2342
+ opts.initSelection = function (element, callback) {
2343
+ var selected = element.find("option").filter(function() { return this.selected && !this.disabled });
2344
+ // a single select box always has a value, no need to null check 'selected'
2345
+ callback(self.optionToData(selected));
2346
+ };
2347
+ } else if ("data" in opts) {
2348
+ // install default initSelection when applied to hidden input and data is local
2349
+ opts.initSelection = opts.initSelection || function (element, callback) {
2350
+ var id = element.val();
2351
+ //search in data by id, storing the actual matching item
2352
+ var match = null;
2353
+ opts.query({
2354
+ matcher: function(term, text, el){
2355
+ var is_match = equal(id, opts.id(el));
2356
+ if (is_match) {
2357
+ match = el;
2358
+ }
2359
+ return is_match;
2360
+ },
2361
+ callback: !$.isFunction(callback) ? $.noop : function() {
2362
+ callback(match);
2363
+ }
2364
+ });
2365
+ };
2366
+ }
2367
+
2368
+ return opts;
2369
+ },
2370
+
2371
+ // single
2372
+ getPlaceholder: function() {
2373
+ // if a placeholder is specified on a single select without a valid placeholder option ignore it
2374
+ if (this.select) {
2375
+ if (this.getPlaceholderOption() === undefined) {
2376
+ return undefined;
2377
+ }
2378
+ }
2379
+
2380
+ return this.parent.getPlaceholder.apply(this, arguments);
2381
+ },
2382
+
2383
+ // single
2384
+ setPlaceholder: function () {
2385
+ var placeholder = this.getPlaceholder();
2386
+
2387
+ if (this.isPlaceholderOptionSelected() && placeholder !== undefined) {
2388
+
2389
+ // check for a placeholder option if attached to a select
2390
+ if (this.select && this.getPlaceholderOption() === undefined) return;
2391
+
2392
+ this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(placeholder));
2393
+
2394
+ this.selection.addClass("select2-default");
2395
+
2396
+ this.container.removeClass("select2-allowclear");
2397
+ }
2398
+ },
2399
+
2400
+ // single
2401
+ postprocessResults: function (data, initial, noHighlightUpdate) {
2402
+ var selected = 0, self = this, showSearchInput = true;
2403
+
2404
+ // find the selected element in the result list
2405
+
2406
+ this.findHighlightableChoices().each2(function (i, elm) {
2407
+ if (equal(self.id(elm.data("select2-data")), self.opts.element.val())) {
2408
+ selected = i;
2409
+ return false;
2410
+ }
2411
+ });
2412
+
2413
+ // and highlight it
2414
+ if (noHighlightUpdate !== false) {
2415
+ if (initial === true && selected >= 0) {
2416
+ this.highlight(selected);
2417
+ } else {
2418
+ this.highlight(0);
2419
+ }
2420
+ }
2421
+
2422
+ // hide the search box if this is the first we got the results and there are enough of them for search
2423
+
2424
+ if (initial === true) {
2425
+ var min = this.opts.minimumResultsForSearch;
2426
+ if (min >= 0) {
2427
+ this.showSearch(countResults(data.results) >= min);
2428
+ }
2429
+ }
2430
+ },
2431
+
2432
+ // single
2433
+ showSearch: function(showSearchInput) {
2434
+ if (this.showSearchInput === showSearchInput) return;
2435
+
2436
+ this.showSearchInput = showSearchInput;
2437
+
2438
+ this.dropdown.find(".select2-search").toggleClass("select2-search-hidden", !showSearchInput);
2439
+ this.dropdown.find(".select2-search").toggleClass("select2-offscreen", !showSearchInput);
2440
+ //add "select2-with-searchbox" to the container if search box is shown
2441
+ $(this.dropdown, this.container).toggleClass("select2-with-searchbox", showSearchInput);
2442
+ },
2443
+
2444
+ // single
2445
+ onSelect: function (data, options) {
2446
+
2447
+ if (!this.triggerSelect(data)) { return; }
2448
+
2449
+ var old = this.opts.element.val(),
2450
+ oldData = this.data();
2451
+
2452
+ this.opts.element.val(this.id(data));
2453
+ this.updateSelection(data);
2454
+
2455
+ this.opts.element.trigger({ type: "select2-selected", val: this.id(data), choice: data });
2456
+
2457
+ this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val());
2458
+ this.close();
2459
+
2460
+ if ((!options || !options.noFocus) && this.opts.shouldFocusInput(this)) {
2461
+ this.focusser.focus();
2462
+ }
2463
+
2464
+ if (!equal(old, this.id(data))) {
2465
+ this.triggerChange({ added: data, removed: oldData });
2466
+ }
2467
+ },
2468
+
2469
+ // single
2470
+ updateSelection: function (data) {
2471
+
2472
+ var container=this.selection.find(".select2-chosen"), formatted, cssClass;
2473
+
2474
+ this.selection.data("select2-data", data);
2475
+
2476
+ container.empty();
2477
+ if (data !== null) {
2478
+ formatted=this.opts.formatSelection(data, container, this.opts.escapeMarkup);
2479
+ }
2480
+ if (formatted !== undefined) {
2481
+ container.append(formatted);
2482
+ }
2483
+ cssClass=this.opts.formatSelectionCssClass(data, container);
2484
+ if (cssClass !== undefined) {
2485
+ container.addClass(cssClass);
2486
+ }
2487
+
2488
+ this.selection.removeClass("select2-default");
2489
+
2490
+ if (this.opts.allowClear && this.getPlaceholder() !== undefined) {
2491
+ this.container.addClass("select2-allowclear");
2492
+ }
2493
+ },
2494
+
2495
+ // single
2496
+ val: function () {
2497
+ var val,
2498
+ triggerChange = false,
2499
+ data = null,
2500
+ self = this,
2501
+ oldData = this.data();
2502
+
2503
+ if (arguments.length === 0) {
2504
+ return this.opts.element.val();
2505
+ }
2506
+
2507
+ val = arguments[0];
2508
+
2509
+ if (arguments.length > 1) {
2510
+ triggerChange = arguments[1];
2511
+ }
2512
+
2513
+ if (this.select) {
2514
+ this.select
2515
+ .val(val)
2516
+ .find("option").filter(function() { return this.selected }).each2(function (i, elm) {
2517
+ data = self.optionToData(elm);
2518
+ return false;
2519
+ });
2520
+ this.updateSelection(data);
2521
+ this.setPlaceholder();
2522
+ if (triggerChange) {
2523
+ this.triggerChange({added: data, removed:oldData});
2524
+ }
2525
+ } else {
2526
+ // val is an id. !val is true for [undefined,null,'',0] - 0 is legal
2527
+ if (!val && val !== 0) {
2528
+ this.clear(triggerChange);
2529
+ return;
2530
+ }
2531
+ if (this.opts.initSelection === undefined) {
2532
+ throw new Error("cannot call val() if initSelection() is not defined");
2533
+ }
2534
+ this.opts.element.val(val);
2535
+ this.opts.initSelection(this.opts.element, function(data){
2536
+ self.opts.element.val(!data ? "" : self.id(data));
2537
+ self.updateSelection(data);
2538
+ self.setPlaceholder();
2539
+ if (triggerChange) {
2540
+ self.triggerChange({added: data, removed:oldData});
2541
+ }
2542
+ });
2543
+ }
2544
+ },
2545
+
2546
+ // single
2547
+ clearSearch: function () {
2548
+ this.search.val("");
2549
+ this.focusser.val("");
2550
+ },
2551
+
2552
+ // single
2553
+ data: function(value) {
2554
+ var data,
2555
+ triggerChange = false;
2556
+
2557
+ if (arguments.length === 0) {
2558
+ data = this.selection.data("select2-data");
2559
+ if (data == undefined) data = null;
2560
+ return data;
2561
+ } else {
2562
+ if (arguments.length > 1) {
2563
+ triggerChange = arguments[1];
2564
+ }
2565
+ if (!value) {
2566
+ this.clear(triggerChange);
2567
+ } else {
2568
+ data = this.data();
2569
+ this.opts.element.val(!value ? "" : this.id(value));
2570
+ this.updateSelection(value);
2571
+ if (triggerChange) {
2572
+ this.triggerChange({added: value, removed:data});
2573
+ }
2574
+ }
2575
+ }
2576
+ }
2577
+ });
2578
+
2579
+ MultiSelect2 = clazz(AbstractSelect2, {
2580
+
2581
+ // multi
2582
+ createContainer: function () {
2583
+ var container = $(document.createElement("div")).attr({
2584
+ "class": "select2-container select2-container-multi"
2585
+ }).html([
2586
+ "<ul class='select2-choices'>",
2587
+ " <li class='select2-search-field'>",
2588
+ " <label for='' class='select2-offscreen'></label>",
2589
+ " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>",
2590
+ " </li>",
2591
+ "</ul>",
2592
+ "<div class='select2-drop select2-drop-multi select2-display-none'>",
2593
+ " <ul class='select2-results'>",
2594
+ " </ul>",
2595
+ "</div>"].join(""));
2596
+ return container;
2597
+ },
2598
+
2599
+ // multi
2600
+ prepareOpts: function () {
2601
+ var opts = this.parent.prepareOpts.apply(this, arguments),
2602
+ self=this;
2603
+
2604
+ // TODO validate placeholder is a string if specified
2605
+ if (opts.element.get(0).tagName.toLowerCase() === "select") {
2606
+ // install the selection initializer
2607
+ opts.initSelection = function (element, callback) {
2608
+
2609
+ var data = [];
2610
+
2611
+ element.find("option").filter(function() { return this.selected && !this.disabled }).each2(function (i, elm) {
2612
+ data.push(self.optionToData(elm));
2613
+ });
2614
+ callback(data);
2615
+ };
2616
+ } else if ("data" in opts) {
2617
+ // install default initSelection when applied to hidden input and data is local
2618
+ opts.initSelection = opts.initSelection || function (element, callback) {
2619
+ var ids = splitVal(element.val(), opts.separator, opts.transformVal);
2620
+ //search in data by array of ids, storing matching items in a list
2621
+ var matches = [];
2622
+ opts.query({
2623
+ matcher: function(term, text, el){
2624
+ var is_match = $.grep(ids, function(id) {
2625
+ return equal(id, opts.id(el));
2626
+ }).length;
2627
+ if (is_match) {
2628
+ matches.push(el);
2629
+ }
2630
+ return is_match;
2631
+ },
2632
+ callback: !$.isFunction(callback) ? $.noop : function() {
2633
+ // reorder matches based on the order they appear in the ids array because right now
2634
+ // they are in the order in which they appear in data array
2635
+ var ordered = [];
2636
+ for (var i = 0; i < ids.length; i++) {
2637
+ var id = ids[i];
2638
+ for (var j = 0; j < matches.length; j++) {
2639
+ var match = matches[j];
2640
+ if (equal(id, opts.id(match))) {
2641
+ ordered.push(match);
2642
+ matches.splice(j, 1);
2643
+ break;
2644
+ }
2645
+ }
2646
+ }
2647
+ callback(ordered);
2648
+ }
2649
+ });
2650
+ };
2651
+ }
2652
+
2653
+ return opts;
2654
+ },
2655
+
2656
+ // multi
2657
+ selectChoice: function (choice) {
2658
+
2659
+ var selected = this.container.find(".select2-search-choice-focus");
2660
+ if (selected.length && choice && choice[0] == selected[0]) {
2661
+
2662
+ } else {
2663
+ if (selected.length) {
2664
+ this.opts.element.trigger("choice-deselected", selected);
2665
+ }
2666
+ selected.removeClass("select2-search-choice-focus");
2667
+ if (choice && choice.length) {
2668
+ this.close();
2669
+ choice.addClass("select2-search-choice-focus");
2670
+ this.opts.element.trigger("choice-selected", choice);
2671
+ }
2672
+ }
2673
+ },
2674
+
2675
+ // multi
2676
+ destroy: function() {
2677
+ $("label[for='" + this.search.attr('id') + "']")
2678
+ .attr('for', this.opts.element.attr("id"));
2679
+ this.parent.destroy.apply(this, arguments);
2680
+
2681
+ cleanupJQueryElements.call(this,
2682
+ "searchContainer",
2683
+ "selection"
2684
+ );
2685
+ },
2686
+
2687
+ // multi
2688
+ initContainer: function () {
2689
+
2690
+ var selector = ".select2-choices", selection;
2691
+
2692
+ this.searchContainer = this.container.find(".select2-search-field");
2693
+ this.selection = selection = this.container.find(selector);
2694
+
2695
+ var _this = this;
2696
+ this.selection.on("click", ".select2-container:not(.select2-container-disabled) .select2-search-choice:not(.select2-locked)", function (e) {
2697
+ _this.search[0].focus();
2698
+ _this.selectChoice($(this));
2699
+ });
2700
+
2701
+ // rewrite labels from original element to focusser
2702
+ this.search.attr("id", "s2id_autogen"+nextUid());
2703
+
2704
+ this.search.prev()
2705
+ .text($("label[for='" + this.opts.element.attr("id") + "']").text())
2706
+ .attr('for', this.search.attr('id'));
2707
+ this.opts.element.focus(this.bind(function () { this.focus(); }));
2708
+
2709
+ this.search.on("input paste", this.bind(function() {
2710
+ if (this.search.attr('placeholder') && this.search.val().length == 0) return;
2711
+ if (!this.isInterfaceEnabled()) return;
2712
+ if (!this.opened()) {
2713
+ this.open();
2714
+ }
2715
+ }));
2716
+
2717
+ this.search.attr("tabindex", this.elementTabIndex);
2718
+
2719
+ this.keydowns = 0;
2720
+ this.search.on("keydown", this.bind(function (e) {
2721
+ if (!this.isInterfaceEnabled()) return;
2722
+
2723
+ ++this.keydowns;
2724
+ var selected = selection.find(".select2-search-choice-focus");
2725
+ var prev = selected.prev(".select2-search-choice:not(.select2-locked)");
2726
+ var next = selected.next(".select2-search-choice:not(.select2-locked)");
2727
+ var pos = getCursorInfo(this.search);
2728
+
2729
+ if (selected.length &&
2730
+ (e.which == KEY.LEFT || e.which == KEY.RIGHT || e.which == KEY.BACKSPACE || e.which == KEY.DELETE || e.which == KEY.ENTER)) {
2731
+ var selectedChoice = selected;
2732
+ if (e.which == KEY.LEFT && prev.length) {
2733
+ selectedChoice = prev;
2734
+ }
2735
+ else if (e.which == KEY.RIGHT) {
2736
+ selectedChoice = next.length ? next : null;
2737
+ }
2738
+ else if (e.which === KEY.BACKSPACE) {
2739
+ if (this.unselect(selected.first())) {
2740
+ this.search.width(10);
2741
+ selectedChoice = prev.length ? prev : next;
2742
+ }
2743
+ } else if (e.which == KEY.DELETE) {
2744
+ if (this.unselect(selected.first())) {
2745
+ this.search.width(10);
2746
+ selectedChoice = next.length ? next : null;
2747
+ }
2748
+ } else if (e.which == KEY.ENTER) {
2749
+ selectedChoice = null;
2750
+ }
2751
+
2752
+ this.selectChoice(selectedChoice);
2753
+ killEvent(e);
2754
+ if (!selectedChoice || !selectedChoice.length) {
2755
+ this.open();
2756
+ }
2757
+ return;
2758
+ } else if (((e.which === KEY.BACKSPACE && this.keydowns == 1)
2759
+ || e.which == KEY.LEFT) && (pos.offset == 0 && !pos.length)) {
2760
+
2761
+ this.selectChoice(selection.find(".select2-search-choice:not(.select2-locked)").last());
2762
+ killEvent(e);
2763
+ return;
2764
+ } else {
2765
+ this.selectChoice(null);
2766
+ }
2767
+
2768
+ if (this.opened()) {
2769
+ switch (e.which) {
2770
+ case KEY.UP:
2771
+ case KEY.DOWN:
2772
+ this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
2773
+ killEvent(e);
2774
+ return;
2775
+ case KEY.ENTER:
2776
+ this.selectHighlighted();
2777
+ killEvent(e);
2778
+ return;
2779
+ case KEY.TAB:
2780
+ this.selectHighlighted({noFocus:true});
2781
+ this.close();
2782
+ return;
2783
+ case KEY.ESC:
2784
+ this.cancel(e);
2785
+ killEvent(e);
2786
+ return;
2787
+ }
2788
+ }
2789
+
2790
+ if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e)
2791
+ || e.which === KEY.BACKSPACE || e.which === KEY.ESC) {
2792
+ return;
2793
+ }
2794
+
2795
+ if (e.which === KEY.ENTER) {
2796
+ if (this.opts.openOnEnter === false) {
2797
+ return;
2798
+ } else if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
2799
+ return;
2800
+ }
2801
+ }
2802
+
2803
+ this.open();
2804
+
2805
+ if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) {
2806
+ // prevent the page from scrolling
2807
+ killEvent(e);
2808
+ }
2809
+
2810
+ if (e.which === KEY.ENTER) {
2811
+ // prevent form from being submitted
2812
+ killEvent(e);
2813
+ }
2814
+
2815
+ }));
2816
+
2817
+ this.search.on("keyup", this.bind(function (e) {
2818
+ this.keydowns = 0;
2819
+ this.resizeSearch();
2820
+ })
2821
+ );
2822
+
2823
+ this.search.on("blur", this.bind(function(e) {
2824
+ this.container.removeClass("select2-container-active");
2825
+ this.search.removeClass("select2-focused");
2826
+ this.selectChoice(null);
2827
+ if (!this.opened()) this.clearSearch();
2828
+ e.stopImmediatePropagation();
2829
+ this.opts.element.trigger($.Event("select2-blur"));
2830
+ }));
2831
+
2832
+ this.container.on("click", selector, this.bind(function (e) {
2833
+ if (!this.isInterfaceEnabled()) return;
2834
+ if ($(e.target).closest(".select2-search-choice").length > 0) {
2835
+ // clicked inside a select2 search choice, do not open
2836
+ return;
2837
+ }
2838
+ this.selectChoice(null);
2839
+ this.clearPlaceholder();
2840
+ if (!this.container.hasClass("select2-container-active")) {
2841
+ this.opts.element.trigger($.Event("select2-focus"));
2842
+ }
2843
+ this.open();
2844
+ this.focusSearch();
2845
+ e.preventDefault();
2846
+ }));
2847
+
2848
+ this.container.on("focus", selector, this.bind(function () {
2849
+ if (!this.isInterfaceEnabled()) return;
2850
+ if (!this.container.hasClass("select2-container-active")) {
2851
+ this.opts.element.trigger($.Event("select2-focus"));
2852
+ }
2853
+ this.container.addClass("select2-container-active");
2854
+ this.dropdown.addClass("select2-drop-active");
2855
+ this.clearPlaceholder();
2856
+ }));
2857
+
2858
+ this.initContainerWidth();
2859
+ this.opts.element.hide();
2860
+
2861
+ // set the placeholder if necessary
2862
+ this.clearSearch();
2863
+ },
2864
+
2865
+ // multi
2866
+ enableInterface: function() {
2867
+ if (this.parent.enableInterface.apply(this, arguments)) {
2868
+ this.search.prop("disabled", !this.isInterfaceEnabled());
2869
+ }
2870
+ },
2871
+
2872
+ // multi
2873
+ initSelection: function () {
2874
+ var data;
2875
+ if (this.opts.element.val() === "" && this.opts.element.text() === "") {
2876
+ this.updateSelection([]);
2877
+ this.close();
2878
+ // set the placeholder if necessary
2879
+ this.clearSearch();
2880
+ }
2881
+ if (this.select || this.opts.element.val() !== "") {
2882
+ var self = this;
2883
+ this.opts.initSelection.call(null, this.opts.element, function(data){
2884
+ if (data !== undefined && data !== null) {
2885
+ self.updateSelection(data);
2886
+ self.close();
2887
+ // set the placeholder if necessary
2888
+ self.clearSearch();
2889
+ }
2890
+ });
2891
+ }
2892
+ },
2893
+
2894
+ // multi
2895
+ clearSearch: function () {
2896
+ var placeholder = this.getPlaceholder(),
2897
+ maxWidth = this.getMaxSearchWidth();
2898
+
2899
+ if (placeholder !== undefined && this.getVal().length === 0 && this.search.hasClass("select2-focused") === false) {
2900
+ this.search.val(placeholder).addClass("select2-default");
2901
+ // stretch the search box to full width of the container so as much of the placeholder is visible as possible
2902
+ // we could call this.resizeSearch(), but we do not because that requires a sizer and we do not want to create one so early because of a firefox bug, see #944
2903
+ this.search.width(maxWidth > 0 ? maxWidth : this.container.css("width"));
2904
+ } else {
2905
+ this.search.val("").width(10);
2906
+ }
2907
+ },
2908
+
2909
+ // multi
2910
+ clearPlaceholder: function () {
2911
+ if (this.search.hasClass("select2-default")) {
2912
+ this.search.val("").removeClass("select2-default");
2913
+ }
2914
+ },
2915
+
2916
+ // multi
2917
+ opening: function () {
2918
+ this.clearPlaceholder(); // should be done before super so placeholder is not used to search
2919
+ this.resizeSearch();
2920
+
2921
+ this.parent.opening.apply(this, arguments);
2922
+
2923
+ this.focusSearch();
2924
+
2925
+ // initializes search's value with nextSearchTerm (if defined by user)
2926
+ // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter
2927
+ if(this.search.val() === "") {
2928
+ if(this.nextSearchTerm != undefined){
2929
+ this.search.val(this.nextSearchTerm);
2930
+ this.search.select();
2931
+ }
2932
+ }
2933
+
2934
+ this.updateResults(true);
2935
+ if (this.opts.shouldFocusInput(this)) {
2936
+ this.search.focus();
2937
+ }
2938
+ this.opts.element.trigger($.Event("select2-open"));
2939
+ },
2940
+
2941
+ // multi
2942
+ close: function () {
2943
+ if (!this.opened()) return;
2944
+ this.parent.close.apply(this, arguments);
2945
+ },
2946
+
2947
+ // multi
2948
+ focus: function () {
2949
+ this.close();
2950
+ this.search.focus();
2951
+ },
2952
+
2953
+ // multi
2954
+ isFocused: function () {
2955
+ return this.search.hasClass("select2-focused");
2956
+ },
2957
+
2958
+ // multi
2959
+ updateSelection: function (data) {
2960
+ var ids = [], filtered = [], self = this;
2961
+
2962
+ // filter out duplicates
2963
+ $(data).each(function () {
2964
+ if (indexOf(self.id(this), ids) < 0) {
2965
+ ids.push(self.id(this));
2966
+ filtered.push(this);
2967
+ }
2968
+ });
2969
+ data = filtered;
2970
+
2971
+ this.selection.find(".select2-search-choice").remove();
2972
+ $(data).each(function () {
2973
+ self.addSelectedChoice(this);
2974
+ });
2975
+ self.postprocessResults();
2976
+ },
2977
+
2978
+ // multi
2979
+ tokenize: function() {
2980
+ var input = this.search.val();
2981
+ input = this.opts.tokenizer.call(this, input, this.data(), this.bind(this.onSelect), this.opts);
2982
+ if (input != null && input != undefined) {
2983
+ this.search.val(input);
2984
+ if (input.length > 0) {
2985
+ this.open();
2986
+ }
2987
+ }
2988
+
2989
+ },
2990
+
2991
+ // multi
2992
+ onSelect: function (data, options) {
2993
+
2994
+ if (!this.triggerSelect(data) || data.text === "") { return; }
2995
+
2996
+ this.addSelectedChoice(data);
2997
+
2998
+ this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data });
2999
+
3000
+ // keep track of the search's value before it gets cleared
3001
+ this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val());
3002
+
3003
+ this.clearSearch();
3004
+ this.updateResults();
3005
+
3006
+ if (this.select || !this.opts.closeOnSelect) this.postprocessResults(data, false, this.opts.closeOnSelect===true);
3007
+
3008
+ if (this.opts.closeOnSelect) {
3009
+ this.close();
3010
+ this.search.width(10);
3011
+ } else {
3012
+ if (this.countSelectableResults()>0) {
3013
+ this.search.width(10);
3014
+ this.resizeSearch();
3015
+ if (this.getMaximumSelectionSize() > 0 && this.val().length >= this.getMaximumSelectionSize()) {
3016
+ // if we reached max selection size repaint the results so choices
3017
+ // are replaced with the max selection reached message
3018
+ this.updateResults(true);
3019
+ } else {
3020
+ // initializes search's value with nextSearchTerm and update search result
3021
+ if(this.nextSearchTerm != undefined){
3022
+ this.search.val(this.nextSearchTerm);
3023
+ this.updateResults();
3024
+ this.search.select();
3025
+ }
3026
+ }
3027
+ this.positionDropdown();
3028
+ } else {
3029
+ // if nothing left to select close
3030
+ this.close();
3031
+ this.search.width(10);
3032
+ }
3033
+ }
3034
+
3035
+ // since its not possible to select an element that has already been
3036
+ // added we do not need to check if this is a new element before firing change
3037
+ this.triggerChange({ added: data });
3038
+
3039
+ if (!options || !options.noFocus)
3040
+ this.focusSearch();
3041
+ },
3042
+
3043
+ // multi
3044
+ cancel: function () {
3045
+ this.close();
3046
+ this.focusSearch();
3047
+ },
3048
+
3049
+ addSelectedChoice: function (data) {
3050
+ var enableChoice = !data.locked,
3051
+ enabledItem = $(
3052
+ "<li class='select2-search-choice'>" +
3053
+ " <div></div>" +
3054
+ " <a href='#' class='select2-search-choice-close' tabindex='-1'></a>" +
3055
+ "</li>"),
3056
+ disabledItem = $(
3057
+ "<li class='select2-search-choice select2-locked'>" +
3058
+ "<div></div>" +
3059
+ "</li>");
3060
+ var choice = enableChoice ? enabledItem : disabledItem,
3061
+ id = this.id(data),
3062
+ val = this.getVal(),
3063
+ formatted,
3064
+ cssClass;
3065
+
3066
+ formatted=this.opts.formatSelection(data, choice.find("div"), this.opts.escapeMarkup);
3067
+ if (formatted != undefined) {
3068
+ choice.find("div").replaceWith($("<div></div>").html(formatted));
3069
+ }
3070
+ cssClass=this.opts.formatSelectionCssClass(data, choice.find("div"));
3071
+ if (cssClass != undefined) {
3072
+ choice.addClass(cssClass);
3073
+ }
3074
+
3075
+ if(enableChoice){
3076
+ choice.find(".select2-search-choice-close")
3077
+ .on("mousedown", killEvent)
3078
+ .on("click dblclick", this.bind(function (e) {
3079
+ if (!this.isInterfaceEnabled()) return;
3080
+
3081
+ this.unselect($(e.target));
3082
+ this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
3083
+ killEvent(e);
3084
+ this.close();
3085
+ this.focusSearch();
3086
+ })).on("focus", this.bind(function () {
3087
+ if (!this.isInterfaceEnabled()) return;
3088
+ this.container.addClass("select2-container-active");
3089
+ this.dropdown.addClass("select2-drop-active");
3090
+ }));
3091
+ }
3092
+
3093
+ choice.data("select2-data", data);
3094
+ choice.insertBefore(this.searchContainer);
3095
+
3096
+ val.push(id);
3097
+ this.setVal(val);
3098
+ },
3099
+
3100
+ // multi
3101
+ unselect: function (selected) {
3102
+ var val = this.getVal(),
3103
+ data,
3104
+ index;
3105
+ selected = selected.closest(".select2-search-choice");
3106
+
3107
+ if (selected.length === 0) {
3108
+ throw "Invalid argument: " + selected + ". Must be .select2-search-choice";
3109
+ }
3110
+
3111
+ data = selected.data("select2-data");
3112
+
3113
+ if (!data) {
3114
+ // prevent a race condition when the 'x' is clicked really fast repeatedly the event can be queued
3115
+ // and invoked on an element already removed
3116
+ return;
3117
+ }
3118
+
3119
+ var evt = $.Event("select2-removing");
3120
+ evt.val = this.id(data);
3121
+ evt.choice = data;
3122
+ this.opts.element.trigger(evt);
3123
+
3124
+ if (evt.isDefaultPrevented()) {
3125
+ return false;
3126
+ }
3127
+
3128
+ while((index = indexOf(this.id(data), val)) >= 0) {
3129
+ val.splice(index, 1);
3130
+ this.setVal(val);
3131
+ if (this.select) this.postprocessResults();
3132
+ }
3133
+
3134
+ selected.remove();
3135
+
3136
+ this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data });
3137
+ this.triggerChange({ removed: data });
3138
+
3139
+ return true;
3140
+ },
3141
+
3142
+ // multi
3143
+ postprocessResults: function (data, initial, noHighlightUpdate) {
3144
+ var val = this.getVal(),
3145
+ choices = this.results.find(".select2-result"),
3146
+ compound = this.results.find(".select2-result-with-children"),
3147
+ self = this;
3148
+
3149
+ choices.each2(function (i, choice) {
3150
+ var id = self.id(choice.data("select2-data"));
3151
+ if (indexOf(id, val) >= 0) {
3152
+ choice.addClass("select2-selected");
3153
+ // mark all children of the selected parent as selected
3154
+ choice.find(".select2-result-selectable").addClass("select2-selected");
3155
+ }
3156
+ });
3157
+
3158
+ compound.each2(function(i, choice) {
3159
+ // hide an optgroup if it doesn't have any selectable children
3160
+ if (!choice.is('.select2-result-selectable')
3161
+ && choice.find(".select2-result-selectable:not(.select2-selected)").length === 0) {
3162
+ choice.addClass("select2-selected");
3163
+ }
3164
+ });
3165
+
3166
+ if (this.highlight() == -1 && noHighlightUpdate !== false && this.opts.closeOnSelect === true){
3167
+ self.highlight(0);
3168
+ }
3169
+
3170
+ //If all results are chosen render formatNoMatches
3171
+ if(!this.opts.createSearchChoice && !choices.filter('.select2-result:not(.select2-selected)').length > 0){
3172
+ if(!data || data && !data.more && this.results.find(".select2-no-results").length === 0) {
3173
+ if (checkFormatter(self.opts.formatNoMatches, "formatNoMatches")) {
3174
+ this.results.append("<li class='select2-no-results'>" + evaluate(self.opts.formatNoMatches, self.opts.element, self.search.val()) + "</li>");
3175
+ }
3176
+ }
3177
+ }
3178
+
3179
+ },
3180
+
3181
+ // multi
3182
+ getMaxSearchWidth: function() {
3183
+ return this.selection.width() - getSideBorderPadding(this.search);
3184
+ },
3185
+
3186
+ // multi
3187
+ resizeSearch: function () {
3188
+ var minimumWidth, left, maxWidth, containerLeft, searchWidth,
3189
+ sideBorderPadding = getSideBorderPadding(this.search);
3190
+
3191
+ minimumWidth = measureTextWidth(this.search) + 10;
3192
+
3193
+ left = this.search.offset().left;
3194
+
3195
+ maxWidth = this.selection.width();
3196
+ containerLeft = this.selection.offset().left;
3197
+
3198
+ searchWidth = maxWidth - (left - containerLeft) - sideBorderPadding;
3199
+
3200
+ if (searchWidth < minimumWidth) {
3201
+ searchWidth = maxWidth - sideBorderPadding;
3202
+ }
3203
+
3204
+ if (searchWidth < 40) {
3205
+ searchWidth = maxWidth - sideBorderPadding;
3206
+ }
3207
+
3208
+ if (searchWidth <= 0) {
3209
+ searchWidth = minimumWidth;
3210
+ }
3211
+
3212
+ this.search.width(Math.floor(searchWidth));
3213
+ },
3214
+
3215
+ // multi
3216
+ getVal: function () {
3217
+ var val;
3218
+ if (this.select) {
3219
+ val = this.select.val();
3220
+ return val === null ? [] : val;
3221
+ } else {
3222
+ val = this.opts.element.val();
3223
+ return splitVal(val, this.opts.separator, this.opts.transformVal);
3224
+ }
3225
+ },
3226
+
3227
+ // multi
3228
+ setVal: function (val) {
3229
+ var unique;
3230
+ if (this.select) {
3231
+ this.select.val(val);
3232
+ } else {
3233
+ unique = [];
3234
+ // filter out duplicates
3235
+ $(val).each(function () {
3236
+ if (indexOf(this, unique) < 0) unique.push(this);
3237
+ });
3238
+ this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator));
3239
+ }
3240
+ },
3241
+
3242
+ // multi
3243
+ buildChangeDetails: function (old, current) {
3244
+ var current = current.slice(0),
3245
+ old = old.slice(0);
3246
+
3247
+ // remove intersection from each array
3248
+ for (var i = 0; i < current.length; i++) {
3249
+ for (var j = 0; j < old.length; j++) {
3250
+ if (equal(this.opts.id(current[i]), this.opts.id(old[j]))) {
3251
+ current.splice(i, 1);
3252
+ if(i>0){
3253
+ i--;
3254
+ }
3255
+ old.splice(j, 1);
3256
+ j--;
3257
+ }
3258
+ }
3259
+ }
3260
+
3261
+ return {added: current, removed: old};
3262
+ },
3263
+
3264
+
3265
+ // multi
3266
+ val: function (val, triggerChange) {
3267
+ var oldData, self=this;
3268
+
3269
+ if (arguments.length === 0) {
3270
+ return this.getVal();
3271
+ }
3272
+
3273
+ oldData=this.data();
3274
+ if (!oldData.length) oldData=[];
3275
+
3276
+ // val is an id. !val is true for [undefined,null,'',0] - 0 is legal
3277
+ if (!val && val !== 0) {
3278
+ this.opts.element.val("");
3279
+ this.updateSelection([]);
3280
+ this.clearSearch();
3281
+ if (triggerChange) {
3282
+ this.triggerChange({added: this.data(), removed: oldData});
3283
+ }
3284
+ return;
3285
+ }
3286
+
3287
+ // val is a list of ids
3288
+ this.setVal(val);
3289
+
3290
+ if (this.select) {
3291
+ this.opts.initSelection(this.select, this.bind(this.updateSelection));
3292
+ if (triggerChange) {
3293
+ this.triggerChange(this.buildChangeDetails(oldData, this.data()));
3294
+ }
3295
+ } else {
3296
+ if (this.opts.initSelection === undefined) {
3297
+ throw new Error("val() cannot be called if initSelection() is not defined");
3298
+ }
3299
+
3300
+ this.opts.initSelection(this.opts.element, function(data){
3301
+ var ids=$.map(data, self.id);
3302
+ self.setVal(ids);
3303
+ self.updateSelection(data);
3304
+ self.clearSearch();
3305
+ if (triggerChange) {
3306
+ self.triggerChange(self.buildChangeDetails(oldData, self.data()));
3307
+ }
3308
+ });
3309
+ }
3310
+ this.clearSearch();
3311
+ },
3312
+
3313
+ // multi
3314
+ onSortStart: function() {
3315
+ if (this.select) {
3316
+ throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead.");
3317
+ }
3318
+
3319
+ // collapse search field into 0 width so its container can be collapsed as well
3320
+ this.search.width(0);
3321
+ // hide the container
3322
+ this.searchContainer.hide();
3323
+ },
3324
+
3325
+ // multi
3326
+ onSortEnd:function() {
3327
+
3328
+ var val=[], self=this;
3329
+
3330
+ // show search and move it to the end of the list
3331
+ this.searchContainer.show();
3332
+ // make sure the search container is the last item in the list
3333
+ this.searchContainer.appendTo(this.searchContainer.parent());
3334
+ // since we collapsed the width in dragStarted, we resize it here
3335
+ this.resizeSearch();
3336
+
3337
+ // update selection
3338
+ this.selection.find(".select2-search-choice").each(function() {
3339
+ val.push(self.opts.id($(this).data("select2-data")));
3340
+ });
3341
+ this.setVal(val);
3342
+ this.triggerChange();
3343
+ },
3344
+
3345
+ // multi
3346
+ data: function(values, triggerChange) {
3347
+ var self=this, ids, old;
3348
+ if (arguments.length === 0) {
3349
+ return this.selection
3350
+ .children(".select2-search-choice")
3351
+ .map(function() { return $(this).data("select2-data"); })
3352
+ .get();
3353
+ } else {
3354
+ old = this.data();
3355
+ if (!values) { values = []; }
3356
+ ids = $.map(values, function(e) { return self.opts.id(e); });
3357
+ this.setVal(ids);
3358
+ this.updateSelection(values);
3359
+ this.clearSearch();
3360
+ if (triggerChange) {
3361
+ this.triggerChange(this.buildChangeDetails(old, this.data()));
3362
+ }
3363
+ }
3364
+ }
3365
+ });
3366
+
3367
+ $.fn.select2 = function () {
3368
+
3369
+ var args = Array.prototype.slice.call(arguments, 0),
3370
+ opts,
3371
+ select2,
3372
+ method, value, multiple,
3373
+ allowedMethods = ["val", "destroy", "opened", "open", "close", "focus", "isFocused", "container", "dropdown", "onSortStart", "onSortEnd", "enable", "disable", "readonly", "positionDropdown", "data", "search"],
3374
+ valueMethods = ["opened", "isFocused", "container", "dropdown"],
3375
+ propertyMethods = ["val", "data"],
3376
+ methodsMap = { search: "externalSearch" };
3377
+
3378
+ this.each(function () {
3379
+ if (args.length === 0 || typeof(args[0]) === "object") {
3380
+ opts = args.length === 0 ? {} : $.extend({}, args[0]);
3381
+ opts.element = $(this);
3382
+
3383
+ if (opts.element.get(0).tagName.toLowerCase() === "select") {
3384
+ multiple = opts.element.prop("multiple");
3385
+ } else {
3386
+ multiple = opts.multiple || false;
3387
+ if ("tags" in opts) {opts.multiple = multiple = true;}
3388
+ }
3389
+
3390
+ select2 = multiple ? new window.Select2["class"].multi() : new window.Select2["class"].single();
3391
+ select2.init(opts);
3392
+ } else if (typeof(args[0]) === "string") {
3393
+
3394
+ if (indexOf(args[0], allowedMethods) < 0) {
3395
+ throw "Unknown method: " + args[0];
3396
+ }
3397
+
3398
+ value = undefined;
3399
+ select2 = $(this).data("select2");
3400
+ if (select2 === undefined) return;
3401
+
3402
+ method=args[0];
3403
+
3404
+ if (method === "container") {
3405
+ value = select2.container;
3406
+ } else if (method === "dropdown") {
3407
+ value = select2.dropdown;
3408
+ } else {
3409
+ if (methodsMap[method]) method = methodsMap[method];
3410
+
3411
+ value = select2[method].apply(select2, args.slice(1));
3412
+ }
3413
+ if (indexOf(args[0], valueMethods) >= 0
3414
+ || (indexOf(args[0], propertyMethods) >= 0 && args.length == 1)) {
3415
+ return false; // abort the iteration, ready to return first matched value
3416
+ }
3417
+ } else {
3418
+ throw "Invalid arguments to select2 plugin: " + args;
3419
+ }
3420
+ });
3421
+ return (value === undefined) ? this : value;
3422
+ };
3423
+
3424
+ // plugin defaults, accessible to users
3425
+ $.fn.select2.defaults = {
3426
+ width: "copy",
3427
+ loadMorePadding: 0,
3428
+ closeOnSelect: true,
3429
+ openOnEnter: true,
3430
+ containerCss: {},
3431
+ dropdownCss: {},
3432
+ containerCssClass: "",
3433
+ dropdownCssClass: "",
3434
+ formatResult: function(result, container, query, escapeMarkup) {
3435
+ var markup=[];
3436
+ markMatch(this.text(result), query.term, markup, escapeMarkup);
3437
+ return markup.join("");
3438
+ },
3439
+ transformVal: function(val) {
3440
+ return $.trim(val);
3441
+ },
3442
+ formatSelection: function (data, container, escapeMarkup) {
3443
+ return data ? escapeMarkup(this.text(data)) : undefined;
3444
+ },
3445
+ sortResults: function (results, container, query) {
3446
+ return results;
3447
+ },
3448
+ formatResultCssClass: function(data) {return data.css;},
3449
+ formatSelectionCssClass: function(data, container) {return undefined;},
3450
+ minimumResultsForSearch: 0,
3451
+ minimumInputLength: 0,
3452
+ maximumInputLength: null,
3453
+ maximumSelectionSize: 0,
3454
+ id: function (e) { return e == undefined ? null : e.id; },
3455
+ text: function (e) {
3456
+ if (e && this.data && this.data.text) {
3457
+ if ($.isFunction(this.data.text)) {
3458
+ return this.data.text(e);
3459
+ } else {
3460
+ return e[this.data.text];
3461
+ }
3462
+ } else {
3463
+ return e.text;
3464
+ }
3465
+ },
3466
+ matcher: function(term, text) {
3467
+ return stripDiacritics(''+text).toUpperCase().indexOf(stripDiacritics(''+term).toUpperCase()) >= 0;
3468
+ },
3469
+ separator: ",",
3470
+ tokenSeparators: [],
3471
+ tokenizer: defaultTokenizer,
3472
+ escapeMarkup: defaultEscapeMarkup,
3473
+ blurOnChange: false,
3474
+ selectOnBlur: false,
3475
+ adaptContainerCssClass: function(c) { return c; },
3476
+ adaptDropdownCssClass: function(c) { return null; },
3477
+ nextSearchTerm: function(selectedObject, currentSearchTerm) { return undefined; },
3478
+ searchInputPlaceholder: '',
3479
+ createSearchChoicePosition: 'top',
3480
+ shouldFocusInput: function (instance) {
3481
+ // Attempt to detect touch devices
3482
+ var supportsTouchEvents = (('ontouchstart' in window) ||
3483
+ (navigator.msMaxTouchPoints > 0));
3484
+
3485
+ // Only devices which support touch events should be special cased
3486
+ if (!supportsTouchEvents) {
3487
+ return true;
3488
+ }
3489
+
3490
+ // Never focus the input if search is disabled
3491
+ if (instance.opts.minimumResultsForSearch < 0) {
3492
+ return false;
3493
+ }
3494
+
3495
+ return true;
3496
+ }
3497
+ };
3498
+
3499
+ $.fn.select2.locales = [];
3500
+
3501
+ $.fn.select2.locales['en'] = {
3502
+ formatMatches: function (matches) { if (matches === 1) { return "One result is available, press enter to select it."; } return matches + " results are available, use up and down arrow keys to navigate."; },
3503
+ formatNoMatches: function () { return "No matches found"; },
3504
+ formatAjaxError: function (jqXHR, textStatus, errorThrown) { return "Loading failed"; },
3505
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " or more character" + (n == 1 ? "" : "s"); },
3506
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Please delete " + n + " character" + (n == 1 ? "" : "s"); },
3507
+ formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); },
3508
+ formatLoadMore: function (pageNumber) { return "Loading more results…"; },
3509
+ formatSearching: function () { return "Searching…"; }
3510
+ };
3511
+
3512
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['en']);
3513
+
3514
+ $.fn.select2.ajaxDefaults = {
3515
+ transport: $.ajax,
3516
+ params: {
3517
+ type: "GET",
3518
+ cache: false,
3519
+ dataType: "json"
3520
+ }
3521
+ };
3522
+
3523
+ // exports
3524
+ window.Select2 = {
3525
+ query: {
3526
+ ajax: ajax,
3527
+ local: local,
3528
+ tags: tags
3529
+ }, util: {
3530
+ debounce: debounce,
3531
+ markMatch: markMatch,
3532
+ escapeMarkup: defaultEscapeMarkup,
3533
+ stripDiacritics: stripDiacritics
3534
+ }, "class": {
3535
+ "abstract": AbstractSelect2,
3536
+ "single": SingleSelect2,
3537
+ "multi": MultiSelect2
3538
+ }
3539
+ };
3540
+
3541
+ }(jQuery));
assets/deps/select2-3.5.2/select2.min.js CHANGED
@@ -1,23 +1,23 @@
1
- /*
2
- Copyright 2014 Igor Vaynberg
3
-
4
- Version: 3.5.2 Timestamp: Sat Nov 1 14:43:36 EDT 2014
5
-
6
- This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
7
- General Public License version 2 (the "GPL License"). You may choose either license to govern your
8
- use of this software only upon the condition that you accept all of the terms of either the Apache
9
- License or the GPL License.
10
-
11
- You may obtain a copy of the Apache License and the GPL License at:
12
-
13
- http://www.apache.org/licenses/LICENSE-2.0
14
- http://www.gnu.org/licenses/gpl-2.0.html
15
-
16
- Unless required by applicable law or agreed to in writing, software distributed under the Apache License
17
- or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
18
- either express or implied. See the Apache License and the GPL License for the specific language governing
19
- permissions and limitations under the Apache License and the GPL License.
20
- */
21
- !function(a){"undefined"==typeof a.fn.each2&&a.extend(a.fn,{each2:function(b){for(var c=a([0]),d=-1,e=this.length;++d<e&&(c.context=c[0]=this[d])&&b.call(c[0],d,c)!==!1;);return this}})}(jQuery),function(a,b){"use strict";function n(b){var c=a(document.createTextNode(""));b.before(c),c.before(b),c.remove()}function o(a){function b(a){return m[a]||a}return a.replace(/[^\u0000-\u007E]/g,b)}function p(a,b){for(var c=0,d=b.length;d>c;c+=1)if(r(a,b[c]))return c;return-1}function q(){var b=a(l);b.appendTo(document.body);var c={width:b.width()-b[0].clientWidth,height:b.height()-b[0].clientHeight};return b.remove(),c}function r(a,c){return a===c?!0:a===b||c===b?!1:null===a||null===c?!1:a.constructor===String?a+""==c+"":c.constructor===String?c+""==a+"":!1}function s(a,b,c){var d,e,f;if(null===a||a.length<1)return[];for(d=a.split(b),e=0,f=d.length;f>e;e+=1)d[e]=c(d[e]);return d}function t(a){return a.outerWidth(!1)-a.width()}function u(c){var d="keyup-change-value";c.on("keydown",function(){a.data(c,d)===b&&a.data(c,d,c.val())}),c.on("keyup",function(){var e=a.data(c,d);e!==b&&c.val()!==e&&(a.removeData(c,d),c.trigger("keyup-change"))})}function v(c){c.on("mousemove",function(c){var d=h;(d===b||d.x!==c.pageX||d.y!==c.pageY)&&a(c.target).trigger("mousemove-filtered",c)})}function w(a,c,d){d=d||b;var e;return function(){var b=arguments;window.clearTimeout(e),e=window.setTimeout(function(){c.apply(d,b)},a)}}function x(a,b){var c=w(a,function(a){b.trigger("scroll-debounced",a)});b.on("scroll",function(a){p(a.target,b.get())>=0&&c(a)})}function y(a){a[0]!==document.activeElement&&window.setTimeout(function(){var d,b=a[0],c=a.val().length;a.focus();var e=b.offsetWidth>0||b.offsetHeight>0;e&&b===document.activeElement&&(b.setSelectionRange?b.setSelectionRange(c,c):b.createTextRange&&(d=b.createTextRange(),d.collapse(!1),d.select()))},0)}function z(b){b=a(b)[0];var c=0,d=0;if("selectionStart"in b)c=b.selectionStart,d=b.selectionEnd-c;else if("selection"in document){b.focus();var e=document.selection.createRange();d=document.selection.createRange().text.length,e.moveStart("character",-b.value.length),c=e.text.length-d}return{offset:c,length:d}}function A(a){a.preventDefault(),a.stopPropagation()}function B(a){a.preventDefault(),a.stopImmediatePropagation()}function C(b){if(!g){var c=b[0].currentStyle||window.getComputedStyle(b[0],null);g=a(document.createElement("div")).css({position:"absolute",left:"-10000px",top:"-10000px",display:"none",fontSize:c.fontSize,fontFamily:c.fontFamily,fontStyle:c.fontStyle,fontWeight:c.fontWeight,letterSpacing:c.letterSpacing,textTransform:c.textTransform,whiteSpace:"nowrap"}),g.attr("class","select2-sizer"),a(document.body).append(g)}return g.text(b.val()),g.width()}function D(b,c,d){var e,g,f=[];e=a.trim(b.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each2(function(){0===this.indexOf("select2-")&&f.push(this)})),e=a.trim(c.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each2(function(){0!==this.indexOf("select2-")&&(g=d(this),g&&f.push(g))})),b.attr("class",f.join(" "))}function E(a,b,c,d){var e=o(a.toUpperCase()).indexOf(o(b.toUpperCase())),f=b.length;return 0>e?(c.push(d(a)),void 0):(c.push(d(a.substring(0,e))),c.push("<span class='select2-match'>"),c.push(d(a.substring(e,e+f))),c.push("</span>"),c.push(d(a.substring(e+f,a.length))),void 0)}function F(a){var b={"\\":"&#92;","&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#47;"};return String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})}function G(c){var d,e=null,f=c.quietMillis||100,g=c.url,h=this;return function(i){window.clearTimeout(d),d=window.setTimeout(function(){var d=c.data,f=g,j=c.transport||a.fn.select2.ajaxDefaults.transport,k={type:c.type||"GET",cache:c.cache||!1,jsonpCallback:c.jsonpCallback||b,dataType:c.dataType||"json"},l=a.extend({},a.fn.select2.ajaxDefaults.params,k);d=d?d.call(h,i.term,i.page,i.context):null,f="function"==typeof f?f.call(h,i.term,i.page,i.context):f,e&&"function"==typeof e.abort&&e.abort(),c.params&&(a.isFunction(c.params)?a.extend(l,c.params.call(h)):a.extend(l,c.params)),a.extend(l,{url:f,dataType:c.dataType,data:d,success:function(a){var b=c.results(a,i.page,i);i.callback(b)},error:function(a,b,c){var d={hasError:!0,jqXHR:a,textStatus:b,errorThrown:c};i.callback(d)}}),e=j.call(h,l)},f)}}function H(b){var d,e,c=b,f=function(a){return""+a.text};a.isArray(c)&&(e=c,c={results:e}),a.isFunction(c)===!1&&(e=c,c=function(){return e});var g=c();return g.text&&(f=g.text,a.isFunction(f)||(d=g.text,f=function(a){return a[d]})),function(b){var g,d=b.term,e={results:[]};return""===d?(b.callback(c()),void 0):(g=function(c,e){var h,i;if(c=c[0],c.children){h={};for(i in c)c.hasOwnProperty(i)&&(h[i]=c[i]);h.children=[],a(c.children).each2(function(a,b){g(b,h.children)}),(h.children.length||b.matcher(d,f(h),c))&&e.push(h)}else b.matcher(d,f(c),c)&&e.push(c)},a(c().results).each2(function(a,b){g(b,e.results)}),b.callback(e),void 0)}}function I(c){var d=a.isFunction(c);return function(e){var f=e.term,g={results:[]},h=d?c(e):c;a.isArray(h)&&(a(h).each(function(){var a=this.text!==b,c=a?this.text:this;(""===f||e.matcher(f,c))&&g.results.push(a?this:{id:this,text:this})}),e.callback(g))}}function J(b,c){if(a.isFunction(b))return!0;if(!b)return!1;if("string"==typeof b)return!0;throw new Error(c+" must be a string, function, or falsy value")}function K(b,c){if(a.isFunction(b)){var d=Array.prototype.slice.call(arguments,2);return b.apply(c,d)}return b}function L(b){var c=0;return a.each(b,function(a,b){b.children?c+=L(b.children):c++}),c}function M(a,c,d,e){var h,i,j,k,l,f=a,g=!1;if(!e.createSearchChoice||!e.tokenSeparators||e.tokenSeparators.length<1)return b;for(;;){for(i=-1,j=0,k=e.tokenSeparators.length;k>j&&(l=e.tokenSeparators[j],i=a.indexOf(l),!(i>=0));j++);if(0>i)break;if(h=a.substring(0,i),a=a.substring(i+l.length),h.length>0&&(h=e.createSearchChoice.call(this,h,c),h!==b&&null!==h&&e.id(h)!==b&&null!==e.id(h))){for(g=!1,j=0,k=c.length;k>j;j++)if(r(e.id(h),e.id(c[j]))){g=!0;break}g||d(h)}}return f!==a?a:void 0}function N(){var b=this;a.each(arguments,function(a,c){b[c].remove(),b[c]=null})}function O(b,c){var d=function(){};return d.prototype=new b,d.prototype.constructor=d,d.prototype.parent=b.prototype,d.prototype=a.extend(d.prototype,c),d}if(window.Select2===b){var c,d,e,f,g,i,j,h={x:0,y:0},k={TAB:9,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,SHIFT:16,CTRL:17,ALT:18,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,BACKSPACE:8,DELETE:46,isArrow:function(a){switch(a=a.which?a.which:a){case k.LEFT:case k.RIGHT:case k.UP:case k.DOWN:return!0}return!1},isControl:function(a){var b=a.which;switch(b){case k.SHIFT:case k.CTRL:case k.ALT:return!0}return a.metaKey?!0:!1},isFunctionKey:function(a){return a=a.which?a.which:a,a>=112&&123>=a}},l="<div class='select2-measure-scrollbar'></div>",m={"\u24b6":"A","\uff21":"A","\xc0":"A","\xc1":"A","\xc2":"A","\u1ea6":"A","\u1ea4":"A","\u1eaa":"A","\u1ea8":"A","\xc3":"A","\u0100":"A","\u0102":"A","\u1eb0":"A","\u1eae":"A","\u1eb4":"A","\u1eb2":"A","\u0226":"A","\u01e0":"A","\xc4":"A","\u01de":"A","\u1ea2":"A","\xc5":"A","\u01fa":"A","\u01cd":"A","\u0200":"A","\u0202":"A","\u1ea0":"A","\u1eac":"A","\u1eb6":"A","\u1e00":"A","\u0104":"A","\u023a":"A","\u2c6f":"A","\ua732":"AA","\xc6":"AE","\u01fc":"AE","\u01e2":"AE","\ua734":"AO","\ua736":"AU","\ua738":"AV","\ua73a":"AV","\ua73c":"AY","\u24b7":"B","\uff22":"B","\u1e02":"B","\u1e04":"B","\u1e06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24b8":"C","\uff23":"C","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\xc7":"C","\u1e08":"C","\u0187":"C","\u023b":"C","\ua73e":"C","\u24b9":"D","\uff24":"D","\u1e0a":"D","\u010e":"D","\u1e0c":"D","\u1e10":"D","\u1e12":"D","\u1e0e":"D","\u0110":"D","\u018b":"D","\u018a":"D","\u0189":"D","\ua779":"D","\u01f1":"DZ","\u01c4":"DZ","\u01f2":"Dz","\u01c5":"Dz","\u24ba":"E","\uff25":"E","\xc8":"E","\xc9":"E","\xca":"E","\u1ec0":"E","\u1ebe":"E","\u1ec4":"E","\u1ec2":"E","\u1ebc":"E","\u0112":"E","\u1e14":"E","\u1e16":"E","\u0114":"E","\u0116":"E","\xcb":"E","\u1eba":"E","\u011a":"E","\u0204":"E","\u0206":"E","\u1eb8":"E","\u1ec6":"E","\u0228":"E","\u1e1c":"E","\u0118":"E","\u1e18":"E","\u1e1a":"E","\u0190":"E","\u018e":"E","\u24bb":"F","\uff26":"F","\u1e1e":"F","\u0191":"F","\ua77b":"F","\u24bc":"G","\uff27":"G","\u01f4":"G","\u011c":"G","\u1e20":"G","\u011e":"G","\u0120":"G","\u01e6":"G","\u0122":"G","\u01e4":"G","\u0193":"G","\ua7a0":"G","\ua77d":"G","\ua77e":"G","\u24bd":"H","\uff28":"H","\u0124":"H","\u1e22":"H","\u1e26":"H","\u021e":"H","\u1e24":"H","\u1e28":"H","\u1e2a":"H","\u0126":"H","\u2c67":"H","\u2c75":"H","\ua78d":"H","\u24be":"I","\uff29":"I","\xcc":"I","\xcd":"I","\xce":"I","\u0128":"I","\u012a":"I","\u012c":"I","\u0130":"I","\xcf":"I","\u1e2e":"I","\u1ec8":"I","\u01cf":"I","\u0208":"I","\u020a":"I","\u1eca":"I","\u012e":"I","\u1e2c":"I","\u0197":"I","\u24bf":"J","\uff2a":"J","\u0134":"J","\u0248":"J","\u24c0":"K","\uff2b":"K","\u1e30":"K","\u01e8":"K","\u1e32":"K","\u0136":"K","\u1e34":"K","\u0198":"K","\u2c69":"K","\ua740":"K","\ua742":"K","\ua744":"K","\ua7a2":"K","\u24c1":"L","\uff2c":"L","\u013f":"L","\u0139":"L","\u013d":"L","\u1e36":"L","\u1e38":"L","\u013b":"L","\u1e3c":"L","\u1e3a":"L","\u0141":"L","\u023d":"L","\u2c62":"L","\u2c60":"L","\ua748":"L","\ua746":"L","\ua780":"L","\u01c7":"LJ","\u01c8":"Lj","\u24c2":"M","\uff2d":"M","\u1e3e":"M","\u1e40":"M","\u1e42":"M","\u2c6e":"M","\u019c":"M","\u24c3":"N","\uff2e":"N","\u01f8":"N","\u0143":"N","\xd1":"N","\u1e44":"N","\u0147":"N","\u1e46":"N","\u0145":"N","\u1e4a":"N","\u1e48":"N","\u0220":"N","\u019d":"N","\ua790":"N","\ua7a4":"N","\u01ca":"NJ","\u01cb":"Nj","\u24c4":"O","\uff2f":"O","\xd2":"O","\xd3":"O","\xd4":"O","\u1ed2":"O","\u1ed0":"O","\u1ed6":"O","\u1ed4":"O","\xd5":"O","\u1e4c":"O","\u022c":"O","\u1e4e":"O","\u014c":"O","\u1e50":"O","\u1e52":"O","\u014e":"O","\u022e":"O","\u0230":"O","\xd6":"O","\u022a":"O","\u1ece":"O","\u0150":"O","\u01d1":"O","\u020c":"O","\u020e":"O","\u01a0":"O","\u1edc":"O","\u1eda":"O","\u1ee0":"O","\u1ede":"O","\u1ee2":"O","\u1ecc":"O","\u1ed8":"O","\u01ea":"O","\u01ec":"O","\xd8":"O","\u01fe":"O","\u0186":"O","\u019f":"O","\ua74a":"O","\ua74c":"O","\u01a2":"OI","\ua74e":"OO","\u0222":"OU","\u24c5":"P","\uff30":"P","\u1e54":"P","\u1e56":"P","\u01a4":"P","\u2c63":"P","\ua750":"P","\ua752":"P","\ua754":"P","\u24c6":"Q","\uff31":"Q","\ua756":"Q","\ua758":"Q","\u024a":"Q","\u24c7":"R","\uff32":"R","\u0154":"R","\u1e58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1e5a":"R","\u1e5c":"R","\u0156":"R","\u1e5e":"R","\u024c":"R","\u2c64":"R","\ua75a":"R","\ua7a6":"R","\ua782":"R","\u24c8":"S","\uff33":"S","\u1e9e":"S","\u015a":"S","\u1e64":"S","\u015c":"S","\u1e60":"S","\u0160":"S","\u1e66":"S","\u1e62":"S","\u1e68":"S","\u0218":"S","\u015e":"S","\u2c7e":"S","\ua7a8":"S","\ua784":"S","\u24c9":"T","\uff34":"T","\u1e6a":"T","\u0164":"T","\u1e6c":"T","\u021a":"T","\u0162":"T","\u1e70":"T","\u1e6e":"T","\u0166":"T","\u01ac":"T","\u01ae":"T","\u023e":"T","\ua786":"T","\ua728":"TZ","\u24ca":"U","\uff35":"U","\xd9":"U","\xda":"U","\xdb":"U","\u0168":"U","\u1e78":"U","\u016a":"U","\u1e7a":"U","\u016c":"U","\xdc":"U","\u01db":"U","\u01d7":"U","\u01d5":"U","\u01d9":"U","\u1ee6":"U","\u016e":"U","\u0170":"U","\u01d3":"U","\u0214":"U","\u0216":"U","\u01af":"U","\u1eea":"U","\u1ee8":"U","\u1eee":"U","\u1eec":"U","\u1ef0":"U","\u1ee4":"U","\u1e72":"U","\u0172":"U","\u1e76":"U","\u1e74":"U","\u0244":"U","\u24cb":"V","\uff36":"V","\u1e7c":"V","\u1e7e":"V","\u01b2":"V","\ua75e":"V","\u0245":"V","\ua760":"VY","\u24cc":"W","\uff37":"W","\u1e80":"W","\u1e82":"W","\u0174":"W","\u1e86":"W","\u1e84":"W","\u1e88":"W","\u2c72":"W","\u24cd":"X","\uff38":"X","\u1e8a":"X","\u1e8c":"X","\u24ce":"Y","\uff39":"Y","\u1ef2":"Y","\xdd":"Y","\u0176":"Y","\u1ef8":"Y","\u0232":"Y","\u1e8e":"Y","\u0178":"Y","\u1ef6":"Y","\u1ef4":"Y","\u01b3":"Y","\u024e":"Y","\u1efe":"Y","\u24cf":"Z","\uff3a":"Z","\u0179":"Z","\u1e90":"Z","\u017b":"Z","\u017d":"Z","\u1e92":"Z","\u1e94":"Z","\u01b5":"Z","\u0224":"Z","\u2c7f":"Z","\u2c6b":"Z","\ua762":"Z","\u24d0":"a","\uff41":"a","\u1e9a":"a","\xe0":"a","\xe1":"a","\xe2":"a","\u1ea7":"a","\u1ea5":"a","\u1eab":"a","\u1ea9":"a","\xe3":"a","\u0101":"a","\u0103":"a","\u1eb1":"a","\u1eaf":"a","\u1eb5":"a","\u1eb3":"a","\u0227":"a","\u01e1":"a","\xe4":"a","\u01df":"a","\u1ea3":"a","\xe5":"a","\u01fb":"a","\u01ce":"a","\u0201":"a","\u0203":"a","\u1ea1":"a","\u1ead":"a","\u1eb7":"a","\u1e01":"a","\u0105":"a","\u2c65":"a","\u0250":"a","\ua733":"aa","\xe6":"ae","\u01fd":"ae","\u01e3":"ae","\ua735":"ao","\ua737":"au","\ua739":"av","\ua73b":"av","\ua73d":"ay","\u24d1":"b","\uff42":"b","\u1e03":"b","\u1e05":"b","\u1e07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24d2":"c","\uff43":"c","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\xe7":"c","\u1e09":"c","\u0188":"c","\u023c":"c","\ua73f":"c","\u2184":"c","\u24d3":"d","\uff44":"d","\u1e0b":"d","\u010f":"d","\u1e0d":"d","\u1e11":"d","\u1e13":"d","\u1e0f":"d","\u0111":"d","\u018c":"d","\u0256":"d","\u0257":"d","\ua77a":"d","\u01f3":"dz","\u01c6":"dz","\u24d4":"e","\uff45":"e","\xe8":"e","\xe9":"e","\xea":"e","\u1ec1":"e","\u1ebf":"e","\u1ec5":"e","\u1ec3":"e","\u1ebd":"e","\u0113":"e","\u1e15":"e","\u1e17":"e","\u0115":"e","\u0117":"e","\xeb":"e","\u1ebb":"e","\u011b":"e","\u0205":"e","\u0207":"e","\u1eb9":"e","\u1ec7":"e","\u0229":"e","\u1e1d":"e","\u0119":"e","\u1e19":"e","\u1e1b":"e","\u0247":"e","\u025b":"e","\u01dd":"e","\u24d5":"f","\uff46":"f","\u1e1f":"f","\u0192":"f","\ua77c":"f","\u24d6":"g","\uff47":"g","\u01f5":"g","\u011d":"g","\u1e21":"g","\u011f":"g","\u0121":"g","\u01e7":"g","\u0123":"g","\u01e5":"g","\u0260":"g","\ua7a1":"g","\u1d79":"g","\ua77f":"g","\u24d7":"h","\uff48":"h","\u0125":"h","\u1e23":"h","\u1e27":"h","\u021f":"h","\u1e25":"h","\u1e29":"h","\u1e2b":"h","\u1e96":"h","\u0127":"h","\u2c68":"h","\u2c76":"h","\u0265":"h","\u0195":"hv","\u24d8":"i","\uff49":"i","\xec":"i","\xed":"i","\xee":"i","\u0129":"i","\u012b":"i","\u012d":"i","\xef":"i","\u1e2f":"i","\u1ec9":"i","\u01d0":"i","\u0209":"i","\u020b":"i","\u1ecb":"i","\u012f":"i","\u1e2d":"i","\u0268":"i","\u0131":"i","\u24d9":"j","\uff4a":"j","\u0135":"j","\u01f0":"j","\u0249":"j","\u24da":"k","\uff4b":"k","\u1e31":"k","\u01e9":"k","\u1e33":"k","\u0137":"k","\u1e35":"k","\u0199":"k","\u2c6a":"k","\ua741":"k","\ua743":"k","\ua745":"k","\ua7a3":"k","\u24db":"l","\uff4c":"l","\u0140":"l","\u013a":"l","\u013e":"l","\u1e37":"l","\u1e39":"l","\u013c":"l","\u1e3d":"l","\u1e3b":"l","\u017f":"l","\u0142":"l","\u019a":"l","\u026b":"l","\u2c61":"l","\ua749":"l","\ua781":"l","\ua747":"l","\u01c9":"lj","\u24dc":"m","\uff4d":"m","\u1e3f":"m","\u1e41":"m","\u1e43":"m","\u0271":"m","\u026f":"m","\u24dd":"n","\uff4e":"n","\u01f9":"n","\u0144":"n","\xf1":"n","\u1e45":"n","\u0148":"n","\u1e47":"n","\u0146":"n","\u1e4b":"n","\u1e49":"n","\u019e":"n","\u0272":"n","\u0149":"n","\ua791":"n","\ua7a5":"n","\u01cc":"nj","\u24de":"o","\uff4f":"o","\xf2":"o","\xf3":"o","\xf4":"o","\u1ed3":"o","\u1ed1":"o","\u1ed7":"o","\u1ed5":"o","\xf5":"o","\u1e4d":"o","\u022d":"o","\u1e4f":"o","\u014d":"o","\u1e51":"o","\u1e53":"o","\u014f":"o","\u022f":"o","\u0231":"o","\xf6":"o","\u022b":"o","\u1ecf":"o","\u0151":"o","\u01d2":"o","\u020d":"o","\u020f":"o","\u01a1":"o","\u1edd":"o","\u1edb":"o","\u1ee1":"o","\u1edf":"o","\u1ee3":"o","\u1ecd":"o","\u1ed9":"o","\u01eb":"o","\u01ed":"o","\xf8":"o","\u01ff":"o","\u0254":"o","\ua74b":"o","\ua74d":"o","\u0275":"o","\u01a3":"oi","\u0223":"ou","\ua74f":"oo","\u24df":"p","\uff50":"p","\u1e55":"p","\u1e57":"p","\u01a5":"p","\u1d7d":"p","\ua751":"p","\ua753":"p","\ua755":"p","\u24e0":"q","\uff51":"q","\u024b":"q","\ua757":"q","\ua759":"q","\u24e1":"r","\uff52":"r","\u0155":"r","\u1e59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1e5b":"r","\u1e5d":"r","\u0157":"r","\u1e5f":"r","\u024d":"r","\u027d":"r","\ua75b":"r","\ua7a7":"r","\ua783":"r","\u24e2":"s","\uff53":"s","\xdf":"s","\u015b":"s","\u1e65":"s","\u015d":"s","\u1e61":"s","\u0161":"s","\u1e67":"s","\u1e63":"s","\u1e69":"s","\u0219":"s","\u015f":"s","\u023f":"s","\ua7a9":"s","\ua785":"s","\u1e9b":"s","\u24e3":"t","\uff54":"t","\u1e6b":"t","\u1e97":"t","\u0165":"t","\u1e6d":"t","\u021b":"t","\u0163":"t","\u1e71":"t","\u1e6f":"t","\u0167":"t","\u01ad":"t","\u0288":"t","\u2c66":"t","\ua787":"t","\ua729":"tz","\u24e4":"u","\uff55":"u","\xf9":"u","\xfa":"u","\xfb":"u","\u0169":"u","\u1e79":"u","\u016b":"u","\u1e7b":"u","\u016d":"u","\xfc":"u","\u01dc":"u","\u01d8":"u","\u01d6":"u","\u01da":"u","\u1ee7":"u","\u016f":"u","\u0171":"u","\u01d4":"u","\u0215":"u","\u0217":"u","\u01b0":"u","\u1eeb":"u","\u1ee9":"u","\u1eef":"u","\u1eed":"u","\u1ef1":"u","\u1ee5":"u","\u1e73":"u","\u0173":"u","\u1e77":"u","\u1e75":"u","\u0289":"u","\u24e5":"v","\uff56":"v","\u1e7d":"v","\u1e7f":"v","\u028b":"v","\ua75f":"v","\u028c":"v","\ua761":"vy","\u24e6":"w","\uff57":"w","\u1e81":"w","\u1e83":"w","\u0175":"w","\u1e87":"w","\u1e85":"w","\u1e98":"w","\u1e89":"w","\u2c73":"w","\u24e7":"x","\uff58":"x","\u1e8b":"x","\u1e8d":"x","\u24e8":"y","\uff59":"y","\u1ef3":"y","\xfd":"y","\u0177":"y","\u1ef9":"y","\u0233":"y","\u1e8f":"y","\xff":"y","\u1ef7":"y","\u1e99":"y","\u1ef5":"y","\u01b4":"y","\u024f":"y","\u1eff":"y","\u24e9":"z","\uff5a":"z","\u017a":"z","\u1e91":"z","\u017c":"z","\u017e":"z","\u1e93":"z","\u1e95":"z","\u01b6":"z","\u0225":"z","\u0240":"z","\u2c6c":"z","\ua763":"z","\u0386":"\u0391","\u0388":"\u0395","\u0389":"\u0397","\u038a":"\u0399","\u03aa":"\u0399","\u038c":"\u039f","\u038e":"\u03a5","\u03ab":"\u03a5","\u038f":"\u03a9","\u03ac":"\u03b1","\u03ad":"\u03b5","\u03ae":"\u03b7","\u03af":"\u03b9","\u03ca":"\u03b9","\u0390":"\u03b9","\u03cc":"\u03bf","\u03cd":"\u03c5","\u03cb":"\u03c5","\u03b0":"\u03c5","\u03c9":"\u03c9","\u03c2":"\u03c3"};i=a(document),f=function(){var a=1;return function(){return a++}}(),c=O(Object,{bind:function(a){var b=this;return function(){a.apply(b,arguments)}},init:function(c){var d,e,g=".select2-results";this.opts=c=this.prepareOpts(c),this.id=c.id,c.element.data("select2")!==b&&null!==c.element.data("select2")&&c.element.data("select2").destroy(),this.container=this.createContainer(),this.liveRegion=a(".select2-hidden-accessible"),0==this.liveRegion.length&&(this.liveRegion=a("<span>",{role:"status","aria-live":"polite"}).addClass("select2-hidden-accessible").appendTo(document.body)),this.containerId="s2id_"+(c.element.attr("id")||"autogen"+f()),this.containerEventName=this.containerId.replace(/([.])/g,"_").replace(/([;&,\-\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g,"\\$1"),this.container.attr("id",this.containerId),this.container.attr("title",c.element.attr("title")),this.body=a(document.body),D(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.attr("style",c.element.attr("style")),this.container.css(K(c.containerCss,this.opts.element)),this.container.addClass(K(c.containerCssClass,this.opts.element)),this.elementTabIndex=this.opts.element.attr("tabindex"),this.opts.element.data("select2",this).attr("tabindex","-1").before(this.container).on("click.select2",A),this.container.data("select2",this),this.dropdown=this.container.find(".select2-drop"),D(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(K(c.dropdownCssClass,this.opts.element)),this.dropdown.data("select2",this),this.dropdown.on("click",A),this.results=d=this.container.find(g),this.search=e=this.container.find("input.select2-input"),this.queryCount=0,this.resultsPage=0,this.context=null,this.initContainer(),this.container.on("click",A),v(this.results),this.dropdown.on("mousemove-filtered",g,this.bind(this.highlightUnderEvent)),this.dropdown.on("touchstart touchmove touchend",g,this.bind(function(a){this._touchEvent=!0,this.highlightUnderEvent(a)})),this.dropdown.on("touchmove",g,this.bind(this.touchMoved)),this.dropdown.on("touchstart touchend",g,this.bind(this.clearTouchMoved)),this.dropdown.on("click",this.bind(function(){this._touchEvent&&(this._touchEvent=!1,this.selectHighlighted())})),x(80,this.results),this.dropdown.on("scroll-debounced",g,this.bind(this.loadMoreIfNeeded)),a(this.container).on("change",".select2-input",function(a){a.stopPropagation()}),a(this.dropdown).on("change",".select2-input",function(a){a.stopPropagation()}),a.fn.mousewheel&&d.mousewheel(function(a,b,c,e){var f=d.scrollTop();e>0&&0>=f-e?(d.scrollTop(0),A(a)):0>e&&d.get(0).scrollHeight-d.scrollTop()+e<=d.height()&&(d.scrollTop(d.get(0).scrollHeight-d.height()),A(a))}),u(e),e.on("keyup-change input paste",this.bind(this.updateResults)),e.on("focus",function(){e.addClass("select2-focused")}),e.on("blur",function(){e.removeClass("select2-focused")}),this.dropdown.on("mouseup",g,this.bind(function(b){a(b.target).closest(".select2-result-selectable").length>0&&(this.highlightUnderEvent(b),this.selectHighlighted(b))})),this.dropdown.on("click mouseup mousedown touchstart touchend focusin",function(a){a.stopPropagation()}),this.nextSearchTerm=b,a.isFunction(this.opts.initSelection)&&(this.initSelection(),this.monitorSource()),null!==c.maximumInputLength&&this.search.attr("maxlength",c.maximumInputLength);var h=c.element.prop("disabled");h===b&&(h=!1),this.enable(!h);var i=c.element.prop("readonly");i===b&&(i=!1),this.readonly(i),j=j||q(),this.autofocus=c.element.prop("autofocus"),c.element.prop("autofocus",!1),this.autofocus&&this.focus(),this.search.attr("placeholder",c.searchInputPlaceholder)},destroy:function(){var a=this.opts.element,c=a.data("select2"),d=this;this.close(),a.length&&a[0].detachEvent&&d._sync&&a.each(function(){d._sync&&this.detachEvent("onpropertychange",d._sync)}),this.propertyObserver&&(this.propertyObserver.disconnect(),this.propertyObserver=null),this._sync=null,c!==b&&(c.container.remove(),c.liveRegion.remove(),c.dropdown.remove(),a.show().removeData("select2").off(".select2").prop("autofocus",this.autofocus||!1),this.elementTabIndex?a.attr({tabindex:this.elementTabIndex}):a.removeAttr("tabindex"),a.show()),N.call(this,"container","liveRegion","dropdown","results","search")},optionToData:function(a){return a.is("option")?{id:a.prop("value"),text:a.text(),element:a.get(),css:a.attr("class"),disabled:a.prop("disabled"),locked:r(a.attr("locked"),"locked")||r(a.data("locked"),!0)}:a.is("optgroup")?{text:a.attr("label"),children:[],element:a.get(),css:a.attr("class")}:void 0},prepareOpts:function(c){var d,e,g,h,i=this;if(d=c.element,"select"===d.get(0).tagName.toLowerCase()&&(this.select=e=c.element),e&&a.each(["id","multiple","ajax","query","createSearchChoice","initSelection","data","tags"],function(){if(this in c)throw new Error("Option '"+this+"' is not allowed for Select2 when attached to a <select> element.")}),c=a.extend({},{populateResults:function(d,e,g){var h,j=this.opts.id,k=this.liveRegion;h=function(d,e,l){var m,n,o,p,q,r,s,t,u,v;d=c.sortResults(d,e,g);var w=[];for(m=0,n=d.length;n>m;m+=1)o=d[m],q=o.disabled===!0,p=!q&&j(o)!==b,r=o.children&&o.children.length>0,s=a("<li></li>"),s.addClass("select2-results-dept-"+l),s.addClass("select2-result"),s.addClass(p?"select2-result-selectable":"select2-result-unselectable"),q&&s.addClass("select2-disabled"),r&&s.addClass("select2-result-with-children"),s.addClass(i.opts.formatResultCssClass(o)),s.attr("role","presentation"),t=a(document.createElement("div")),t.addClass("select2-result-label"),t.attr("id","select2-result-label-"+f()),t.attr("role","option"),v=c.formatResult(o,t,g,i.opts.escapeMarkup),v!==b&&(t.html(v),s.append(t)),r&&(u=a("<ul></ul>"),u.addClass("select2-result-sub"),h(o.children,u,l+1),s.append(u)),s.data("select2-data",o),w.push(s[0]);e.append(w),k.text(c.formatMatches(d.length))},h(e,d,0)}},a.fn.select2.defaults,c),"function"!=typeof c.id&&(g=c.id,c.id=function(a){return a[g]}),a.isArray(c.element.data("select2Tags"))){if("tags"in c)throw"tags specified as both an attribute 'data-select2-tags' and in options of Select2 "+c.element.attr("id");c.tags=c.element.data("select2Tags")}if(e?(c.query=this.bind(function(a){var f,g,h,c={results:[],more:!1},e=a.term;h=function(b,c){var d;b.is("option")?a.matcher(e,b.text(),b)&&c.push(i.optionToData(b)):b.is("optgroup")&&(d=i.optionToData(b),b.children().each2(function(a,b){h(b,d.children)}),d.children.length>0&&c.push(d))},f=d.children(),this.getPlaceholder()!==b&&f.length>0&&(g=this.getPlaceholderOption(),g&&(f=f.not(g))),f.each2(function(a,b){h(b,c.results)}),a.callback(c)}),c.id=function(a){return a.id}):"query"in c||("ajax"in c?(h=c.element.data("ajax-url"),h&&h.length>0&&(c.ajax.url=h),c.query=G.call(c.element,c.ajax)):"data"in c?c.query=H(c.data):"tags"in c&&(c.query=I(c.tags),c.createSearchChoice===b&&(c.createSearchChoice=function(b){return{id:a.trim(b),text:a.trim(b)}}),c.initSelection===b&&(c.initSelection=function(b,d){var e=[];a(s(b.val(),c.separator,c.transformVal)).each(function(){var b={id:this,text:this},d=c.tags;a.isFunction(d)&&(d=d()),a(d).each(function(){return r(this.id,b.id)?(b=this,!1):void 0}),e.push(b)}),d(e)}))),"function"!=typeof c.query)throw"query function not defined for Select2 "+c.element.attr("id");if("top"===c.createSearchChoicePosition)c.createSearchChoicePosition=function(a,b){a.unshift(b)};else if("bottom"===c.createSearchChoicePosition)c.createSearchChoicePosition=function(a,b){a.push(b)};else if("function"!=typeof c.createSearchChoicePosition)throw"invalid createSearchChoicePosition option must be 'top', 'bottom' or a custom function";return c},monitorSource:function(){var d,c=this.opts.element,e=this;c.on("change.select2",this.bind(function(){this.opts.element.data("select2-change-triggered")!==!0&&this.initSelection()})),this._sync=this.bind(function(){var a=c.prop("disabled");a===b&&(a=!1),this.enable(!a);var d=c.prop("readonly");d===b&&(d=!1),this.readonly(d),this.container&&(D(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.addClass(K(this.opts.containerCssClass,this.opts.element))),this.dropdown&&(D(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(K(this.opts.dropdownCssClass,this.opts.element)))}),c.length&&c[0].attachEvent&&c.each(function(){this.attachEvent("onpropertychange",e._sync)}),d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver,d!==b&&(this.propertyObserver&&(delete this.propertyObserver,this.propertyObserver=null),this.propertyObserver=new d(function(b){a.each(b,e._sync)}),this.propertyObserver.observe(c.get(0),{attributes:!0,subtree:!1}))},triggerSelect:function(b){var c=a.Event("select2-selecting",{val:this.id(b),object:b,choice:b});return this.opts.element.trigger(c),!c.isDefaultPrevented()},triggerChange:function(b){b=b||{},b=a.extend({},b,{type:"change",val:this.val()}),this.opts.element.data("select2-change-triggered",!0),this.opts.element.trigger(b),this.opts.element.data("select2-change-triggered",!1),this.opts.element.click(),this.opts.blurOnChange&&this.opts.element.blur()},isInterfaceEnabled:function(){return this.enabledInterface===!0},enableInterface:function(){var a=this._enabled&&!this._readonly,b=!a;return a===this.enabledInterface?!1:(this.container.toggleClass("select2-container-disabled",b),this.close(),this.enabledInterface=a,!0)},enable:function(a){a===b&&(a=!0),this._enabled!==a&&(this._enabled=a,this.opts.element.prop("disabled",!a),this.enableInterface())},disable:function(){this.enable(!1)},readonly:function(a){a===b&&(a=!1),this._readonly!==a&&(this._readonly=a,this.opts.element.prop("readonly",a),this.enableInterface())},opened:function(){return this.container?this.container.hasClass("select2-dropdown-open"):!1},positionDropdown:function(){var v,w,x,y,z,b=this.dropdown,c=this.container,d=c.offset(),e=c.outerHeight(!1),f=c.outerWidth(!1),g=b.outerHeight(!1),h=a(window),i=h.width(),k=h.height(),l=h.scrollLeft()+i,m=h.scrollTop()+k,n=d.top+e,o=d.left,p=m>=n+g,q=d.top-g>=h.scrollTop(),r=b.outerWidth(!1),s=function(){return l>=o+r},t=function(){return d.left+l+c.outerWidth(!1)>r},u=b.hasClass("select2-drop-above");u?(w=!0,!q&&p&&(x=!0,w=!1)):(w=!1,!p&&q&&(x=!0,w=!0)),x&&(b.hide(),d=this.container.offset(),e=this.container.outerHeight(!1),f=this.container.outerWidth(!1),g=b.outerHeight(!1),l=h.scrollLeft()+i,m=h.scrollTop()+k,n=d.top+e,o=d.left,r=b.outerWidth(!1),b.show(),this.focusSearch()),this.opts.dropdownAutoWidth?(z=a(".select2-results",b)[0],b.addClass("select2-drop-auto-width"),b.css("width",""),r=b.outerWidth(!1)+(z.scrollHeight===z.clientHeight?0:j.width),r>f?f=r:r=f,g=b.outerHeight(!1)):this.container.removeClass("select2-drop-auto-width"),"static"!==this.body.css("position")&&(v=this.body.offset(),n-=v.top,o-=v.left),!s()&&t()&&(o=d.left+this.container.outerWidth(!1)-r),y={left:o,width:f},w?(y.top=d.top-g,y.bottom="auto",this.container.addClass("select2-drop-above"),b.addClass("select2-drop-above")):(y.top=n,y.bottom="auto",this.container.removeClass("select2-drop-above"),b.removeClass("select2-drop-above")),y=a.extend(y,K(this.opts.dropdownCss,this.opts.element)),b.css(y)},shouldOpen:function(){var b;return this.opened()?!1:this._enabled===!1||this._readonly===!0?!1:(b=a.Event("select2-opening"),this.opts.element.trigger(b),!b.isDefaultPrevented())},clearDropdownAlignmentPreference:function(){this.container.removeClass("select2-drop-above"),this.dropdown.removeClass("select2-drop-above")},open:function(){return this.shouldOpen()?(this.opening(),i.on("mousemove.select2Event",function(a){h.x=a.pageX,h.y=a.pageY}),!0):!1},opening:function(){var f,b=this.containerEventName,c="scroll."+b,d="resize."+b,e="orientationchange."+b;this.container.addClass("select2-dropdown-open").addClass("select2-container-active"),this.clearDropdownAlignmentPreference(),this.dropdown[0]!==this.body.children().last()[0]&&this.dropdown.detach().appendTo(this.body),f=a("#select2-drop-mask"),0===f.length&&(f=a(document.createElement("div")),f.attr("id","select2-drop-mask").attr("class","select2-drop-mask"),f.hide(),f.appendTo(this.body),f.on("mousedown touchstart click",function(b){n(f);var d,c=a("#select2-drop");c.length>0&&(d=c.data("select2"),d.opts.selectOnBlur&&d.selectHighlighted({noFocus:!0}),d.close(),b.preventDefault(),b.stopPropagation())})),this.dropdown.prev()[0]!==f[0]&&this.dropdown.before(f),a("#select2-drop").removeAttr("id"),this.dropdown.attr("id","select2-drop"),f.show(),this.positionDropdown(),this.dropdown.show(),this.positionDropdown(),this.dropdown.addClass("select2-drop-active");var g=this;this.container.parents().add(window).each(function(){a(this).on(d+" "+c+" "+e,function(){g.opened()&&g.positionDropdown()})})},close:function(){if(this.opened()){var b=this.containerEventName,c="scroll."+b,d="resize."+b,e="orientationchange."+b;this.container.parents().add(window).each(function(){a(this).off(c).off(d).off(e)}),this.clearDropdownAlignmentPreference(),a("#select2-drop-mask").hide(),this.dropdown.removeAttr("id"),this.dropdown.hide(),this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active"),this.results.empty(),i.off("mousemove.select2Event"),this.clearSearch(),this.search.removeClass("select2-active"),this.opts.element.trigger(a.Event("select2-close"))}},externalSearch:function(a){this.open(),this.search.val(a),this.updateResults(!1)},clearSearch:function(){},getMaximumSelectionSize:function(){return K(this.opts.maximumSelectionSize,this.opts.element)},ensureHighlightVisible:function(){var c,d,e,f,g,h,i,j,b=this.results;if(d=this.highlight(),!(0>d)){if(0==d)return b.scrollTop(0),void 0;c=this.findHighlightableChoices().find(".select2-result-label"),e=a(c[d]),j=(e.offset()||{}).top||0,f=j+e.outerHeight(!0),d===c.length-1&&(i=b.find("li.select2-more-results"),i.length>0&&(f=i.offset().top+i.outerHeight(!0))),g=b.offset().top+b.outerHeight(!1),f>g&&b.scrollTop(b.scrollTop()+(f-g)),h=j-b.offset().top,0>h&&"none"!=e.css("display")&&b.scrollTop(b.scrollTop()+h)}},findHighlightableChoices:function(){return this.results.find(".select2-result-selectable:not(.select2-disabled):not(.select2-selected)")},moveHighlight:function(b){for(var c=this.findHighlightableChoices(),d=this.highlight();d>-1&&d<c.length;){d+=b;
22
- var e=a(c[d]);if(e.hasClass("select2-result-selectable")&&!e.hasClass("select2-disabled")&&!e.hasClass("select2-selected")){this.highlight(d);break}}},highlight:function(b){var d,e,c=this.findHighlightableChoices();return 0===arguments.length?p(c.filter(".select2-highlighted")[0],c.get()):(b>=c.length&&(b=c.length-1),0>b&&(b=0),this.removeHighlight(),d=a(c[b]),d.addClass("select2-highlighted"),this.search.attr("aria-activedescendant",d.find(".select2-result-label").attr("id")),this.ensureHighlightVisible(),this.liveRegion.text(d.text()),e=d.data("select2-data"),e&&this.opts.element.trigger({type:"select2-highlight",val:this.id(e),choice:e}),void 0)},removeHighlight:function(){this.results.find(".select2-highlighted").removeClass("select2-highlighted")},touchMoved:function(){this._touchMoved=!0},clearTouchMoved:function(){this._touchMoved=!1},countSelectableResults:function(){return this.findHighlightableChoices().length},highlightUnderEvent:function(b){var c=a(b.target).closest(".select2-result-selectable");if(c.length>0&&!c.is(".select2-highlighted")){var d=this.findHighlightableChoices();this.highlight(d.index(c))}else 0==c.length&&this.removeHighlight()},loadMoreIfNeeded:function(){var c,a=this.results,b=a.find("li.select2-more-results"),d=this.resultsPage+1,e=this,f=this.search.val(),g=this.context;0!==b.length&&(c=b.offset().top-a.offset().top-a.height(),c<=this.opts.loadMorePadding&&(b.addClass("select2-active"),this.opts.query({element:this.opts.element,term:f,page:d,context:g,matcher:this.opts.matcher,callback:this.bind(function(c){e.opened()&&(e.opts.populateResults.call(this,a,c.results,{term:f,page:d,context:g}),e.postprocessResults(c,!1,!1),c.more===!0?(b.detach().appendTo(a).html(e.opts.escapeMarkup(K(e.opts.formatLoadMore,e.opts.element,d+1))),window.setTimeout(function(){e.loadMoreIfNeeded()},10)):b.remove(),e.positionDropdown(),e.resultsPage=d,e.context=c.context,this.opts.element.trigger({type:"select2-loaded",items:c}))})})))},tokenize:function(){},updateResults:function(c){function m(){d.removeClass("select2-active"),h.positionDropdown(),e.find(".select2-no-results,.select2-selection-limit,.select2-searching").length?h.liveRegion.text(e.text()):h.liveRegion.text(h.opts.formatMatches(e.find('.select2-result-selectable:not(".select2-selected")').length))}function n(a){e.html(a),m()}var g,i,l,d=this.search,e=this.results,f=this.opts,h=this,j=d.val(),k=a.data(this.container,"select2-last-term");if((c===!0||!k||!r(j,k))&&(a.data(this.container,"select2-last-term",j),c===!0||this.showSearchInput!==!1&&this.opened())){l=++this.queryCount;var o=this.getMaximumSelectionSize();if(o>=1&&(g=this.data(),a.isArray(g)&&g.length>=o&&J(f.formatSelectionTooBig,"formatSelectionTooBig")))return n("<li class='select2-selection-limit'>"+K(f.formatSelectionTooBig,f.element,o)+"</li>"),void 0;if(d.val().length<f.minimumInputLength)return J(f.formatInputTooShort,"formatInputTooShort")?n("<li class='select2-no-results'>"+K(f.formatInputTooShort,f.element,d.val(),f.minimumInputLength)+"</li>"):n(""),c&&this.showSearch&&this.showSearch(!0),void 0;if(f.maximumInputLength&&d.val().length>f.maximumInputLength)return J(f.formatInputTooLong,"formatInputTooLong")?n("<li class='select2-no-results'>"+K(f.formatInputTooLong,f.element,d.val(),f.maximumInputLength)+"</li>"):n(""),void 0;f.formatSearching&&0===this.findHighlightableChoices().length&&n("<li class='select2-searching'>"+K(f.formatSearching,f.element)+"</li>"),d.addClass("select2-active"),this.removeHighlight(),i=this.tokenize(),i!=b&&null!=i&&d.val(i),this.resultsPage=1,f.query({element:f.element,term:d.val(),page:this.resultsPage,context:null,matcher:f.matcher,callback:this.bind(function(g){var i;if(l==this.queryCount){if(!this.opened())return this.search.removeClass("select2-active"),void 0;if(g.hasError!==b&&J(f.formatAjaxError,"formatAjaxError"))return n("<li class='select2-ajax-error'>"+K(f.formatAjaxError,f.element,g.jqXHR,g.textStatus,g.errorThrown)+"</li>"),void 0;if(this.context=g.context===b?null:g.context,this.opts.createSearchChoice&&""!==d.val()&&(i=this.opts.createSearchChoice.call(h,d.val(),g.results),i!==b&&null!==i&&h.id(i)!==b&&null!==h.id(i)&&0===a(g.results).filter(function(){return r(h.id(this),h.id(i))}).length&&this.opts.createSearchChoicePosition(g.results,i)),0===g.results.length&&J(f.formatNoMatches,"formatNoMatches"))return n("<li class='select2-no-results'>"+K(f.formatNoMatches,f.element,d.val())+"</li>"),void 0;e.empty(),h.opts.populateResults.call(this,e,g.results,{term:d.val(),page:this.resultsPage,context:null}),g.more===!0&&J(f.formatLoadMore,"formatLoadMore")&&(e.append("<li class='select2-more-results'>"+f.escapeMarkup(K(f.formatLoadMore,f.element,this.resultsPage))+"</li>"),window.setTimeout(function(){h.loadMoreIfNeeded()},10)),this.postprocessResults(g,c),m(),this.opts.element.trigger({type:"select2-loaded",items:g})}})})}},cancel:function(){this.close()},blur:function(){this.opts.selectOnBlur&&this.selectHighlighted({noFocus:!0}),this.close(),this.container.removeClass("select2-container-active"),this.search[0]===document.activeElement&&this.search.blur(),this.clearSearch(),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus")},focusSearch:function(){y(this.search)},selectHighlighted:function(a){if(this._touchMoved)return this.clearTouchMoved(),void 0;var b=this.highlight(),c=this.results.find(".select2-highlighted"),d=c.closest(".select2-result").data("select2-data");d?(this.highlight(b),this.onSelect(d,a)):a&&a.noFocus&&this.close()},getPlaceholder:function(){var a;return this.opts.element.attr("placeholder")||this.opts.element.attr("data-placeholder")||this.opts.element.data("placeholder")||this.opts.placeholder||((a=this.getPlaceholderOption())!==b?a.text():b)},getPlaceholderOption:function(){if(this.select){var c=this.select.children("option").first();if(this.opts.placeholderOption!==b)return"first"===this.opts.placeholderOption&&c||"function"==typeof this.opts.placeholderOption&&this.opts.placeholderOption(this.select);if(""===a.trim(c.text())&&""===c.val())return c}},initContainerWidth:function(){function c(){var c,d,e,f,g,h;if("off"===this.opts.width)return null;if("element"===this.opts.width)return 0===this.opts.element.outerWidth(!1)?"auto":this.opts.element.outerWidth(!1)+"px";if("copy"===this.opts.width||"resolve"===this.opts.width){if(c=this.opts.element.attr("style"),c!==b)for(d=c.split(";"),f=0,g=d.length;g>f;f+=1)if(h=d[f].replace(/\s/g,""),e=h.match(/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i),null!==e&&e.length>=1)return e[1];return"resolve"===this.opts.width?(c=this.opts.element.css("width"),c.indexOf("%")>0?c:0===this.opts.element.outerWidth(!1)?"auto":this.opts.element.outerWidth(!1)+"px"):null}return a.isFunction(this.opts.width)?this.opts.width():this.opts.width}var d=c.call(this);null!==d&&this.container.css("width",d)}}),d=O(c,{createContainer:function(){var b=a(document.createElement("div")).attr({"class":"select2-container"}).html(["<a href='javascript:void(0)' class='select2-choice' tabindex='-1'>"," <span class='select2-chosen'>&#160;</span><abbr class='select2-search-choice-close'></abbr>"," <span class='select2-arrow' role='presentation'><b role='presentation'></b></span>","</a>","<label for='' class='select2-offscreen'></label>","<input class='select2-focusser select2-offscreen' type='text' aria-haspopup='true' role='button' />","<div class='select2-drop select2-display-none'>"," <div class='select2-search'>"," <label for='' class='select2-offscreen'></label>"," <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input' role='combobox' aria-expanded='true'"," aria-autocomplete='list' />"," </div>"," <ul class='select2-results' role='listbox'>"," </ul>","</div>"].join(""));return b},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.focusser.prop("disabled",!this.isInterfaceEnabled())},opening:function(){var c,d,e;this.opts.minimumResultsForSearch>=0&&this.showSearch(!0),this.parent.opening.apply(this,arguments),this.showSearchInput!==!1&&this.search.val(this.focusser.val()),this.opts.shouldFocusInput(this)&&(this.search.focus(),c=this.search.get(0),c.createTextRange?(d=c.createTextRange(),d.collapse(!1),d.select()):c.setSelectionRange&&(e=this.search.val().length,c.setSelectionRange(e,e))),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.focusser.prop("disabled",!0).val(""),this.updateResults(!0),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&(this.parent.close.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},focus:function(){this.opened()?this.close():(this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},isFocused:function(){return this.container.hasClass("select2-container-active")},cancel:function(){this.parent.cancel.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus()},destroy:function(){a("label[for='"+this.focusser.attr("id")+"']").attr("for",this.opts.element.attr("id")),this.parent.destroy.apply(this,arguments),N.call(this,"selection","focusser")},initContainer:function(){var b,g,c=this.container,d=this.dropdown,e=f();this.opts.minimumResultsForSearch<0?this.showSearch(!1):this.showSearch(!0),this.selection=b=c.find(".select2-choice"),this.focusser=c.find(".select2-focusser"),b.find(".select2-chosen").attr("id","select2-chosen-"+e),this.focusser.attr("aria-labelledby","select2-chosen-"+e),this.results.attr("id","select2-results-"+e),this.search.attr("aria-owns","select2-results-"+e),this.focusser.attr("id","s2id_autogen"+e),g=a("label[for='"+this.opts.element.attr("id")+"']"),this.opts.element.focus(this.bind(function(){this.focus()})),this.focusser.prev().text(g.text()).attr("for",this.focusser.attr("id"));var h=this.opts.element.attr("title");this.opts.element.attr("title",h||g.text()),this.focusser.attr("tabindex",this.elementTabIndex),this.search.attr("id",this.focusser.attr("id")+"_search"),this.search.prev().text(a("label[for='"+this.focusser.attr("id")+"']").text()).attr("for",this.search.attr("id")),this.search.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()&&229!=a.keyCode){if(a.which===k.PAGE_UP||a.which===k.PAGE_DOWN)return A(a),void 0;switch(a.which){case k.UP:case k.DOWN:return this.moveHighlight(a.which===k.UP?-1:1),A(a),void 0;case k.ENTER:return this.selectHighlighted(),A(a),void 0;case k.TAB:return this.selectHighlighted({noFocus:!0}),void 0;case k.ESC:return this.cancel(a),A(a),void 0}}})),this.search.on("blur",this.bind(function(){document.activeElement===this.body.get(0)&&window.setTimeout(this.bind(function(){this.opened()&&this.search.focus()}),0)})),this.focusser.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()&&a.which!==k.TAB&&!k.isControl(a)&&!k.isFunctionKey(a)&&a.which!==k.ESC){if(this.opts.openOnEnter===!1&&a.which===k.ENTER)return A(a),void 0;if(a.which==k.DOWN||a.which==k.UP||a.which==k.ENTER&&this.opts.openOnEnter){if(a.altKey||a.ctrlKey||a.shiftKey||a.metaKey)return;return this.open(),A(a),void 0}return a.which==k.DELETE||a.which==k.BACKSPACE?(this.opts.allowClear&&this.clear(),A(a),void 0):void 0}})),u(this.focusser),this.focusser.on("keyup-change input",this.bind(function(a){if(this.opts.minimumResultsForSearch>=0){if(a.stopPropagation(),this.opened())return;this.open()}})),b.on("mousedown touchstart","abbr",this.bind(function(a){this.isInterfaceEnabled()&&(this.clear(),B(a),this.close(),this.selection&&this.selection.focus())})),b.on("mousedown touchstart",this.bind(function(c){n(b),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.opened()?this.close():this.isInterfaceEnabled()&&this.open(),A(c)})),d.on("mousedown touchstart",this.bind(function(){this.opts.shouldFocusInput(this)&&this.search.focus()})),b.on("focus",this.bind(function(a){A(a)})),this.focusser.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})).on("blur",this.bind(function(){this.opened()||(this.container.removeClass("select2-container-active"),this.opts.element.trigger(a.Event("select2-blur")))})),this.search.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})),this.initContainerWidth(),this.opts.element.hide(),this.setPlaceholder()},clear:function(b){var c=this.selection.data("select2-data");if(c){var d=a.Event("select2-clearing");if(this.opts.element.trigger(d),d.isDefaultPrevented())return;var e=this.getPlaceholderOption();this.opts.element.val(e?e.val():""),this.selection.find(".select2-chosen").empty(),this.selection.removeData("select2-data"),this.setPlaceholder(),b!==!1&&(this.opts.element.trigger({type:"select2-removed",val:this.id(c),choice:c}),this.triggerChange({removed:c}))}},initSelection:function(){if(this.isPlaceholderOptionSelected())this.updateSelection(null),this.close(),this.setPlaceholder();else{var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.setPlaceholder(),c.nextSearchTerm=c.opts.nextSearchTerm(a,c.search.val()))})}},isPlaceholderOptionSelected:function(){var a;return this.getPlaceholder()===b?!1:(a=this.getPlaceholderOption())!==b&&a.prop("selected")||""===this.opts.element.val()||this.opts.element.val()===b||null===this.opts.element.val()},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=a.find("option").filter(function(){return this.selected&&!this.disabled});b(c.optionToData(d))}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=c.val(),f=null;b.query({matcher:function(a,c,d){var g=r(e,b.id(d));return g&&(f=d),g},callback:a.isFunction(d)?function(){d(f)}:a.noop})}),b},getPlaceholder:function(){return this.select&&this.getPlaceholderOption()===b?b:this.parent.getPlaceholder.apply(this,arguments)},setPlaceholder:function(){var a=this.getPlaceholder();if(this.isPlaceholderOptionSelected()&&a!==b){if(this.select&&this.getPlaceholderOption()===b)return;this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(a)),this.selection.addClass("select2-default"),this.container.removeClass("select2-allowclear")}},postprocessResults:function(a,b,c){var d=0,e=this;if(this.findHighlightableChoices().each2(function(a,b){return r(e.id(b.data("select2-data")),e.opts.element.val())?(d=a,!1):void 0}),c!==!1&&(b===!0&&d>=0?this.highlight(d):this.highlight(0)),b===!0){var g=this.opts.minimumResultsForSearch;g>=0&&this.showSearch(L(a.results)>=g)}},showSearch:function(b){this.showSearchInput!==b&&(this.showSearchInput=b,this.dropdown.find(".select2-search").toggleClass("select2-search-hidden",!b),this.dropdown.find(".select2-search").toggleClass("select2-offscreen",!b),a(this.dropdown,this.container).toggleClass("select2-with-searchbox",b))},onSelect:function(a,b){if(this.triggerSelect(a)){var c=this.opts.element.val(),d=this.data();this.opts.element.val(this.id(a)),this.updateSelection(a),this.opts.element.trigger({type:"select2-selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.close(),b&&b.noFocus||!this.opts.shouldFocusInput(this)||this.focusser.focus(),r(c,this.id(a))||this.triggerChange({added:a,removed:d})}},updateSelection:function(a){var d,e,c=this.selection.find(".select2-chosen");this.selection.data("select2-data",a),c.empty(),null!==a&&(d=this.opts.formatSelection(a,c,this.opts.escapeMarkup)),d!==b&&c.append(d),e=this.opts.formatSelectionCssClass(a,c),e!==b&&c.addClass(e),this.selection.removeClass("select2-default"),this.opts.allowClear&&this.getPlaceholder()!==b&&this.container.addClass("select2-allowclear")},val:function(){var a,c=!1,d=null,e=this,f=this.data();if(0===arguments.length)return this.opts.element.val();if(a=arguments[0],arguments.length>1&&(c=arguments[1]),this.select)this.select.val(a).find("option").filter(function(){return this.selected}).each2(function(a,b){return d=e.optionToData(b),!1}),this.updateSelection(d),this.setPlaceholder(),c&&this.triggerChange({added:d,removed:f});else{if(!a&&0!==a)return this.clear(c),void 0;if(this.opts.initSelection===b)throw new Error("cannot call val() if initSelection() is not defined");this.opts.element.val(a),this.opts.initSelection(this.opts.element,function(a){e.opts.element.val(a?e.id(a):""),e.updateSelection(a),e.setPlaceholder(),c&&e.triggerChange({added:a,removed:f})})}},clearSearch:function(){this.search.val(""),this.focusser.val("")},data:function(a){var c,d=!1;return 0===arguments.length?(c=this.selection.data("select2-data"),c==b&&(c=null),c):(arguments.length>1&&(d=arguments[1]),a?(c=this.data(),this.opts.element.val(a?this.id(a):""),this.updateSelection(a),d&&this.triggerChange({added:a,removed:c})):this.clear(d),void 0)}}),e=O(c,{createContainer:function(){var b=a(document.createElement("div")).attr({"class":"select2-container select2-container-multi"}).html(["<ul class='select2-choices'>"," <li class='select2-search-field'>"," <label for='' class='select2-offscreen'></label>"," <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>"," </li>","</ul>","<div class='select2-drop select2-drop-multi select2-display-none'>"," <ul class='select2-results'>"," </ul>","</div>"].join(""));return b},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=[];a.find("option").filter(function(){return this.selected&&!this.disabled}).each2(function(a,b){d.push(c.optionToData(b))}),b(d)}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=s(c.val(),b.separator,b.transformVal),f=[];b.query({matcher:function(c,d,g){var h=a.grep(e,function(a){return r(a,b.id(g))}).length;return h&&f.push(g),h},callback:a.isFunction(d)?function(){for(var a=[],c=0;c<e.length;c++)for(var g=e[c],h=0;h<f.length;h++){var i=f[h];if(r(g,b.id(i))){a.push(i),f.splice(h,1);break}}d(a)}:a.noop})}),b},selectChoice:function(a){var b=this.container.find(".select2-search-choice-focus");b.length&&a&&a[0]==b[0]||(b.length&&this.opts.element.trigger("choice-deselected",b),b.removeClass("select2-search-choice-focus"),a&&a.length&&(this.close(),a.addClass("select2-search-choice-focus"),this.opts.element.trigger("choice-selected",a)))},destroy:function(){a("label[for='"+this.search.attr("id")+"']").attr("for",this.opts.element.attr("id")),this.parent.destroy.apply(this,arguments),N.call(this,"searchContainer","selection")},initContainer:function(){var c,b=".select2-choices";this.searchContainer=this.container.find(".select2-search-field"),this.selection=c=this.container.find(b);var d=this;this.selection.on("click",".select2-container:not(.select2-container-disabled) .select2-search-choice:not(.select2-locked)",function(){d.search[0].focus(),d.selectChoice(a(this))}),this.search.attr("id","s2id_autogen"+f()),this.search.prev().text(a("label[for='"+this.opts.element.attr("id")+"']").text()).attr("for",this.search.attr("id")),this.opts.element.focus(this.bind(function(){this.focus()})),this.search.on("input paste",this.bind(function(){this.search.attr("placeholder")&&0==this.search.val().length||this.isInterfaceEnabled()&&(this.opened()||this.open())})),this.search.attr("tabindex",this.elementTabIndex),this.keydowns=0,this.search.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()){++this.keydowns;var b=c.find(".select2-search-choice-focus"),d=b.prev(".select2-search-choice:not(.select2-locked)"),e=b.next(".select2-search-choice:not(.select2-locked)"),f=z(this.search);if(b.length&&(a.which==k.LEFT||a.which==k.RIGHT||a.which==k.BACKSPACE||a.which==k.DELETE||a.which==k.ENTER)){var g=b;return a.which==k.LEFT&&d.length?g=d:a.which==k.RIGHT?g=e.length?e:null:a.which===k.BACKSPACE?this.unselect(b.first())&&(this.search.width(10),g=d.length?d:e):a.which==k.DELETE?this.unselect(b.first())&&(this.search.width(10),g=e.length?e:null):a.which==k.ENTER&&(g=null),this.selectChoice(g),A(a),g&&g.length||this.open(),void 0}if((a.which===k.BACKSPACE&&1==this.keydowns||a.which==k.LEFT)&&0==f.offset&&!f.length)return this.selectChoice(c.find(".select2-search-choice:not(.select2-locked)").last()),A(a),void 0;if(this.selectChoice(null),this.opened())switch(a.which){case k.UP:case k.DOWN:return this.moveHighlight(a.which===k.UP?-1:1),A(a),void 0;case k.ENTER:return this.selectHighlighted(),A(a),void 0;case k.TAB:return this.selectHighlighted({noFocus:!0}),this.close(),void 0;case k.ESC:return this.cancel(a),A(a),void 0}if(a.which!==k.TAB&&!k.isControl(a)&&!k.isFunctionKey(a)&&a.which!==k.BACKSPACE&&a.which!==k.ESC){if(a.which===k.ENTER){if(this.opts.openOnEnter===!1)return;if(a.altKey||a.ctrlKey||a.shiftKey||a.metaKey)return}this.open(),(a.which===k.PAGE_UP||a.which===k.PAGE_DOWN)&&A(a),a.which===k.ENTER&&A(a)}}})),this.search.on("keyup",this.bind(function(){this.keydowns=0,this.resizeSearch()})),this.search.on("blur",this.bind(function(b){this.container.removeClass("select2-container-active"),this.search.removeClass("select2-focused"),this.selectChoice(null),this.opened()||this.clearSearch(),b.stopImmediatePropagation(),this.opts.element.trigger(a.Event("select2-blur"))})),this.container.on("click",b,this.bind(function(b){this.isInterfaceEnabled()&&(a(b.target).closest(".select2-search-choice").length>0||(this.selectChoice(null),this.clearPlaceholder(),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.open(),this.focusSearch(),b.preventDefault()))})),this.container.on("focus",b,this.bind(function(){this.isInterfaceEnabled()&&(this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"),this.clearPlaceholder())})),this.initContainerWidth(),this.opts.element.hide(),this.clearSearch()},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.search.prop("disabled",!this.isInterfaceEnabled())},initSelection:function(){if(""===this.opts.element.val()&&""===this.opts.element.text()&&(this.updateSelection([]),this.close(),this.clearSearch()),this.select||""!==this.opts.element.val()){var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.clearSearch())})}},clearSearch:function(){var a=this.getPlaceholder(),c=this.getMaxSearchWidth();a!==b&&0===this.getVal().length&&this.search.hasClass("select2-focused")===!1?(this.search.val(a).addClass("select2-default"),this.search.width(c>0?c:this.container.css("width"))):this.search.val("").width(10)},clearPlaceholder:function(){this.search.hasClass("select2-default")&&this.search.val("").removeClass("select2-default")},opening:function(){this.clearPlaceholder(),this.resizeSearch(),this.parent.opening.apply(this,arguments),this.focusSearch(),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.updateResults(!0),this.opts.shouldFocusInput(this)&&this.search.focus(),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&this.parent.close.apply(this,arguments)},focus:function(){this.close(),this.search.focus()},isFocused:function(){return this.search.hasClass("select2-focused")},updateSelection:function(b){var c=[],d=[],e=this;a(b).each(function(){p(e.id(this),c)<0&&(c.push(e.id(this)),d.push(this))}),b=d,this.selection.find(".select2-search-choice").remove(),a(b).each(function(){e.addSelectedChoice(this)}),e.postprocessResults()},tokenize:function(){var a=this.search.val();a=this.opts.tokenizer.call(this,a,this.data(),this.bind(this.onSelect),this.opts),null!=a&&a!=b&&(this.search.val(a),a.length>0&&this.open())},onSelect:function(a,c){this.triggerSelect(a)&&""!==a.text&&(this.addSelectedChoice(a),this.opts.element.trigger({type:"selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.clearSearch(),this.updateResults(),(this.select||!this.opts.closeOnSelect)&&this.postprocessResults(a,!1,this.opts.closeOnSelect===!0),this.opts.closeOnSelect?(this.close(),this.search.width(10)):this.countSelectableResults()>0?(this.search.width(10),this.resizeSearch(),this.getMaximumSelectionSize()>0&&this.val().length>=this.getMaximumSelectionSize()?this.updateResults(!0):this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.updateResults(),this.search.select()),this.positionDropdown()):(this.close(),this.search.width(10)),this.triggerChange({added:a}),c&&c.noFocus||this.focusSearch())},cancel:function(){this.close(),this.focusSearch()},addSelectedChoice:function(c){var j,k,d=!c.locked,e=a("<li class='select2-search-choice'> <div></div> <a href='#' class='select2-search-choice-close' tabindex='-1'></a></li>"),f=a("<li class='select2-search-choice select2-locked'><div></div></li>"),g=d?e:f,h=this.id(c),i=this.getVal();j=this.opts.formatSelection(c,g.find("div"),this.opts.escapeMarkup),j!=b&&g.find("div").replaceWith(a("<div></div>").html(j)),k=this.opts.formatSelectionCssClass(c,g.find("div")),k!=b&&g.addClass(k),d&&g.find(".select2-search-choice-close").on("mousedown",A).on("click dblclick",this.bind(function(b){this.isInterfaceEnabled()&&(this.unselect(a(b.target)),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"),A(b),this.close(),this.focusSearch())})).on("focus",this.bind(function(){this.isInterfaceEnabled()&&(this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"))})),g.data("select2-data",c),g.insertBefore(this.searchContainer),i.push(h),this.setVal(i)},unselect:function(b){var d,e,c=this.getVal();if(b=b.closest(".select2-search-choice"),0===b.length)throw"Invalid argument: "+b+". Must be .select2-search-choice";if(d=b.data("select2-data")){var f=a.Event("select2-removing");if(f.val=this.id(d),f.choice=d,this.opts.element.trigger(f),f.isDefaultPrevented())return!1;for(;(e=p(this.id(d),c))>=0;)c.splice(e,1),this.setVal(c),this.select&&this.postprocessResults();return b.remove(),this.opts.element.trigger({type:"select2-removed",val:this.id(d),choice:d}),this.triggerChange({removed:d}),!0}},postprocessResults:function(a,b,c){var d=this.getVal(),e=this.results.find(".select2-result"),f=this.results.find(".select2-result-with-children"),g=this;e.each2(function(a,b){var c=g.id(b.data("select2-data"));p(c,d)>=0&&(b.addClass("select2-selected"),b.find(".select2-result-selectable").addClass("select2-selected"))}),f.each2(function(a,b){b.is(".select2-result-selectable")||0!==b.find(".select2-result-selectable:not(.select2-selected)").length||b.addClass("select2-selected")}),-1==this.highlight()&&c!==!1&&this.opts.closeOnSelect===!0&&g.highlight(0),!this.opts.createSearchChoice&&!e.filter(".select2-result:not(.select2-selected)").length>0&&(!a||a&&!a.more&&0===this.results.find(".select2-no-results").length)&&J(g.opts.formatNoMatches,"formatNoMatches")&&this.results.append("<li class='select2-no-results'>"+K(g.opts.formatNoMatches,g.opts.element,g.search.val())+"</li>")},getMaxSearchWidth:function(){return this.selection.width()-t(this.search)},resizeSearch:function(){var a,b,c,d,e,f=t(this.search);a=C(this.search)+10,b=this.search.offset().left,c=this.selection.width(),d=this.selection.offset().left,e=c-(b-d)-f,a>e&&(e=c-f),40>e&&(e=c-f),0>=e&&(e=a),this.search.width(Math.floor(e))},getVal:function(){var a;return this.select?(a=this.select.val(),null===a?[]:a):(a=this.opts.element.val(),s(a,this.opts.separator,this.opts.transformVal))},setVal:function(b){var c;this.select?this.select.val(b):(c=[],a(b).each(function(){p(this,c)<0&&c.push(this)}),this.opts.element.val(0===c.length?"":c.join(this.opts.separator)))},buildChangeDetails:function(a,b){for(var b=b.slice(0),a=a.slice(0),c=0;c<b.length;c++)for(var d=0;d<a.length;d++)r(this.opts.id(b[c]),this.opts.id(a[d]))&&(b.splice(c,1),c>0&&c--,a.splice(d,1),d--);return{added:b,removed:a}},val:function(c,d){var e,f=this;if(0===arguments.length)return this.getVal();if(e=this.data(),e.length||(e=[]),!c&&0!==c)return this.opts.element.val(""),this.updateSelection([]),this.clearSearch(),d&&this.triggerChange({added:this.data(),removed:e}),void 0;if(this.setVal(c),this.select)this.opts.initSelection(this.select,this.bind(this.updateSelection)),d&&this.triggerChange(this.buildChangeDetails(e,this.data()));else{if(this.opts.initSelection===b)throw new Error("val() cannot be called if initSelection() is not defined");this.opts.initSelection(this.opts.element,function(b){var c=a.map(b,f.id);f.setVal(c),f.updateSelection(b),f.clearSearch(),d&&f.triggerChange(f.buildChangeDetails(e,f.data()))})}this.clearSearch()},onSortStart:function(){if(this.select)throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead.");this.search.width(0),this.searchContainer.hide()},onSortEnd:function(){var b=[],c=this;this.searchContainer.show(),this.searchContainer.appendTo(this.searchContainer.parent()),this.resizeSearch(),this.selection.find(".select2-search-choice").each(function(){b.push(c.opts.id(a(this).data("select2-data")))}),this.setVal(b),this.triggerChange()},data:function(b,c){var e,f,d=this;return 0===arguments.length?this.selection.children(".select2-search-choice").map(function(){return a(this).data("select2-data")}).get():(f=this.data(),b||(b=[]),e=a.map(b,function(a){return d.opts.id(a)}),this.setVal(e),this.updateSelection(b),this.clearSearch(),c&&this.triggerChange(this.buildChangeDetails(f,this.data())),void 0)}}),a.fn.select2=function(){var d,e,f,g,h,c=Array.prototype.slice.call(arguments,0),i=["val","destroy","opened","open","close","focus","isFocused","container","dropdown","onSortStart","onSortEnd","enable","disable","readonly","positionDropdown","data","search"],j=["opened","isFocused","container","dropdown"],k=["val","data"],l={search:"externalSearch"};return this.each(function(){if(0===c.length||"object"==typeof c[0])d=0===c.length?{}:a.extend({},c[0]),d.element=a(this),"select"===d.element.get(0).tagName.toLowerCase()?h=d.element.prop("multiple"):(h=d.multiple||!1,"tags"in d&&(d.multiple=h=!0)),e=h?new window.Select2["class"].multi:new window.Select2["class"].single,e.init(d);else{if("string"!=typeof c[0])throw"Invalid arguments to select2 plugin: "+c;if(p(c[0],i)<0)throw"Unknown method: "+c[0];if(g=b,e=a(this).data("select2"),e===b)return;if(f=c[0],"container"===f?g=e.container:"dropdown"===f?g=e.dropdown:(l[f]&&(f=l[f]),g=e[f].apply(e,c.slice(1))),p(c[0],j)>=0||p(c[0],k)>=0&&1==c.length)return!1}}),g===b?this:g},a.fn.select2.defaults={width:"copy",loadMorePadding:0,closeOnSelect:!0,openOnEnter:!0,containerCss:{},dropdownCss:{},containerCssClass:"",dropdownCssClass:"",formatResult:function(a,b,c,d){var e=[];return E(this.text(a),c.term,e,d),e.join("")},transformVal:function(b){return a.trim(b)},formatSelection:function(a,c,d){return a?d(this.text(a)):b},sortResults:function(a){return a},formatResultCssClass:function(a){return a.css},formatSelectionCssClass:function(){return b},minimumResultsForSearch:0,minimumInputLength:0,maximumInputLength:null,maximumSelectionSize:0,id:function(a){return a==b?null:a.id},text:function(b){return b&&this.data&&this.data.text?a.isFunction(this.data.text)?this.data.text(b):b[this.data.text]:b.text
23
  },matcher:function(a,b){return o(""+b).toUpperCase().indexOf(o(""+a).toUpperCase())>=0},separator:",",tokenSeparators:[],tokenizer:M,escapeMarkup:F,blurOnChange:!1,selectOnBlur:!1,adaptContainerCssClass:function(a){return a},adaptDropdownCssClass:function(){return null},nextSearchTerm:function(){return b},searchInputPlaceholder:"",createSearchChoicePosition:"top",shouldFocusInput:function(a){var b="ontouchstart"in window||navigator.msMaxTouchPoints>0;return b?a.opts.minimumResultsForSearch<0?!1:!0:!0}},a.fn.select2.locales=[],a.fn.select2.locales.en={formatMatches:function(a){return 1===a?"One result is available, press enter to select it.":a+" results are available, use up and down arrow keys to navigate."},formatNoMatches:function(){return"No matches found"},formatAjaxError:function(){return"Loading failed"},formatInputTooShort:function(a,b){var c=b-a.length;return"Please enter "+c+" or more character"+(1==c?"":"s")},formatInputTooLong:function(a,b){var c=a.length-b;return"Please delete "+c+" character"+(1==c?"":"s")},formatSelectionTooBig:function(a){return"You can only select "+a+" item"+(1==a?"":"s")},formatLoadMore:function(){return"Loading more results\u2026"},formatSearching:function(){return"Searching\u2026"}},a.extend(a.fn.select2.defaults,a.fn.select2.locales.en),a.fn.select2.ajaxDefaults={transport:a.ajax,params:{type:"GET",cache:!1,dataType:"json"}},window.Select2={query:{ajax:G,local:H,tags:I},util:{debounce:w,markMatch:E,escapeMarkup:F,stripDiacritics:o},"class":{"abstract":c,single:d,multi:e}}}}(jQuery);
1
+ /*
2
+ Copyright 2014 Igor Vaynberg
3
+
4
+ Version: 3.5.2 Timestamp: Sat Nov 1 14:43:36 EDT 2014
5
+
6
+ This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
7
+ General Public License version 2 (the "GPL License"). You may choose either license to govern your
8
+ use of this software only upon the condition that you accept all of the terms of either the Apache
9
+ License or the GPL License.
10
+
11
+ You may obtain a copy of the Apache License and the GPL License at:
12
+
13
+ http://www.apache.org/licenses/LICENSE-2.0
14
+ http://www.gnu.org/licenses/gpl-2.0.html
15
+
16
+ Unless required by applicable law or agreed to in writing, software distributed under the Apache License
17
+ or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
18
+ either express or implied. See the Apache License and the GPL License for the specific language governing
19
+ permissions and limitations under the Apache License and the GPL License.
20
+ */
21
+ !function(a){"undefined"==typeof a.fn.each2&&a.extend(a.fn,{each2:function(b){for(var c=a([0]),d=-1,e=this.length;++d<e&&(c.context=c[0]=this[d])&&b.call(c[0],d,c)!==!1;);return this}})}(jQuery),function(a,b){"use strict";function n(b){var c=a(document.createTextNode(""));b.before(c),c.before(b),c.remove()}function o(a){function b(a){return m[a]||a}return a.replace(/[^\u0000-\u007E]/g,b)}function p(a,b){for(var c=0,d=b.length;d>c;c+=1)if(r(a,b[c]))return c;return-1}function q(){var b=a(l);b.appendTo(document.body);var c={width:b.width()-b[0].clientWidth,height:b.height()-b[0].clientHeight};return b.remove(),c}function r(a,c){return a===c?!0:a===b||c===b?!1:null===a||null===c?!1:a.constructor===String?a+""==c+"":c.constructor===String?c+""==a+"":!1}function s(a,b,c){var d,e,f;if(null===a||a.length<1)return[];for(d=a.split(b),e=0,f=d.length;f>e;e+=1)d[e]=c(d[e]);return d}function t(a){return a.outerWidth(!1)-a.width()}function u(c){var d="keyup-change-value";c.on("keydown",function(){a.data(c,d)===b&&a.data(c,d,c.val())}),c.on("keyup",function(){var e=a.data(c,d);e!==b&&c.val()!==e&&(a.removeData(c,d),c.trigger("keyup-change"))})}function v(c){c.on("mousemove",function(c){var d=h;(d===b||d.x!==c.pageX||d.y!==c.pageY)&&a(c.target).trigger("mousemove-filtered",c)})}function w(a,c,d){d=d||b;var e;return function(){var b=arguments;window.clearTimeout(e),e=window.setTimeout(function(){c.apply(d,b)},a)}}function x(a,b){var c=w(a,function(a){b.trigger("scroll-debounced",a)});b.on("scroll",function(a){p(a.target,b.get())>=0&&c(a)})}function y(a){a[0]!==document.activeElement&&window.setTimeout(function(){var d,b=a[0],c=a.val().length;a.focus();var e=b.offsetWidth>0||b.offsetHeight>0;e&&b===document.activeElement&&(b.setSelectionRange?b.setSelectionRange(c,c):b.createTextRange&&(d=b.createTextRange(),d.collapse(!1),d.select()))},0)}function z(b){b=a(b)[0];var c=0,d=0;if("selectionStart"in b)c=b.selectionStart,d=b.selectionEnd-c;else if("selection"in document){b.focus();var e=document.selection.createRange();d=document.selection.createRange().text.length,e.moveStart("character",-b.value.length),c=e.text.length-d}return{offset:c,length:d}}function A(a){a.preventDefault(),a.stopPropagation()}function B(a){a.preventDefault(),a.stopImmediatePropagation()}function C(b){if(!g){var c=b[0].currentStyle||window.getComputedStyle(b[0],null);g=a(document.createElement("div")).css({position:"absolute",left:"-10000px",top:"-10000px",display:"none",fontSize:c.fontSize,fontFamily:c.fontFamily,fontStyle:c.fontStyle,fontWeight:c.fontWeight,letterSpacing:c.letterSpacing,textTransform:c.textTransform,whiteSpace:"nowrap"}),g.attr("class","select2-sizer"),a(document.body).append(g)}return g.text(b.val()),g.width()}function D(b,c,d){var e,g,f=[];e=a.trim(b.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each2(function(){0===this.indexOf("select2-")&&f.push(this)})),e=a.trim(c.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each2(function(){0!==this.indexOf("select2-")&&(g=d(this),g&&f.push(g))})),b.attr("class",f.join(" "))}function E(a,b,c,d){var e=o(a.toUpperCase()).indexOf(o(b.toUpperCase())),f=b.length;return 0>e?(c.push(d(a)),void 0):(c.push(d(a.substring(0,e))),c.push("<span class='select2-match'>"),c.push(d(a.substring(e,e+f))),c.push("</span>"),c.push(d(a.substring(e+f,a.length))),void 0)}function F(a){var b={"\\":"&#92;","&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#47;"};return String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})}function G(c){var d,e=null,f=c.quietMillis||100,g=c.url,h=this;return function(i){window.clearTimeout(d),d=window.setTimeout(function(){var d=c.data,f=g,j=c.transport||a.fn.select2.ajaxDefaults.transport,k={type:c.type||"GET",cache:c.cache||!1,jsonpCallback:c.jsonpCallback||b,dataType:c.dataType||"json"},l=a.extend({},a.fn.select2.ajaxDefaults.params,k);d=d?d.call(h,i.term,i.page,i.context):null,f="function"==typeof f?f.call(h,i.term,i.page,i.context):f,e&&"function"==typeof e.abort&&e.abort(),c.params&&(a.isFunction(c.params)?a.extend(l,c.params.call(h)):a.extend(l,c.params)),a.extend(l,{url:f,dataType:c.dataType,data:d,success:function(a){var b=c.results(a,i.page,i);i.callback(b)},error:function(a,b,c){var d={hasError:!0,jqXHR:a,textStatus:b,errorThrown:c};i.callback(d)}}),e=j.call(h,l)},f)}}function H(b){var d,e,c=b,f=function(a){return""+a.text};a.isArray(c)&&(e=c,c={results:e}),a.isFunction(c)===!1&&(e=c,c=function(){return e});var g=c();return g.text&&(f=g.text,a.isFunction(f)||(d=g.text,f=function(a){return a[d]})),function(b){var g,d=b.term,e={results:[]};return""===d?(b.callback(c()),void 0):(g=function(c,e){var h,i;if(c=c[0],c.children){h={};for(i in c)c.hasOwnProperty(i)&&(h[i]=c[i]);h.children=[],a(c.children).each2(function(a,b){g(b,h.children)}),(h.children.length||b.matcher(d,f(h),c))&&e.push(h)}else b.matcher(d,f(c),c)&&e.push(c)},a(c().results).each2(function(a,b){g(b,e.results)}),b.callback(e),void 0)}}function I(c){var d=a.isFunction(c);return function(e){var f=e.term,g={results:[]},h=d?c(e):c;a.isArray(h)&&(a(h).each(function(){var a=this.text!==b,c=a?this.text:this;(""===f||e.matcher(f,c))&&g.results.push(a?this:{id:this,text:this})}),e.callback(g))}}function J(b,c){if(a.isFunction(b))return!0;if(!b)return!1;if("string"==typeof b)return!0;throw new Error(c+" must be a string, function, or falsy value")}function K(b,c){if(a.isFunction(b)){var d=Array.prototype.slice.call(arguments,2);return b.apply(c,d)}return b}function L(b){var c=0;return a.each(b,function(a,b){b.children?c+=L(b.children):c++}),c}function M(a,c,d,e){var h,i,j,k,l,f=a,g=!1;if(!e.createSearchChoice||!e.tokenSeparators||e.tokenSeparators.length<1)return b;for(;;){for(i=-1,j=0,k=e.tokenSeparators.length;k>j&&(l=e.tokenSeparators[j],i=a.indexOf(l),!(i>=0));j++);if(0>i)break;if(h=a.substring(0,i),a=a.substring(i+l.length),h.length>0&&(h=e.createSearchChoice.call(this,h,c),h!==b&&null!==h&&e.id(h)!==b&&null!==e.id(h))){for(g=!1,j=0,k=c.length;k>j;j++)if(r(e.id(h),e.id(c[j]))){g=!0;break}g||d(h)}}return f!==a?a:void 0}function N(){var b=this;a.each(arguments,function(a,c){b[c].remove(),b[c]=null})}function O(b,c){var d=function(){};return d.prototype=new b,d.prototype.constructor=d,d.prototype.parent=b.prototype,d.prototype=a.extend(d.prototype,c),d}if(window.Select2===b){var c,d,e,f,g,i,j,h={x:0,y:0},k={TAB:9,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,SHIFT:16,CTRL:17,ALT:18,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,BACKSPACE:8,DELETE:46,isArrow:function(a){switch(a=a.which?a.which:a){case k.LEFT:case k.RIGHT:case k.UP:case k.DOWN:return!0}return!1},isControl:function(a){var b=a.which;switch(b){case k.SHIFT:case k.CTRL:case k.ALT:return!0}return a.metaKey?!0:!1},isFunctionKey:function(a){return a=a.which?a.which:a,a>=112&&123>=a}},l="<div class='select2-measure-scrollbar'></div>",m={"\u24b6":"A","\uff21":"A","\xc0":"A","\xc1":"A","\xc2":"A","\u1ea6":"A","\u1ea4":"A","\u1eaa":"A","\u1ea8":"A","\xc3":"A","\u0100":"A","\u0102":"A","\u1eb0":"A","\u1eae":"A","\u1eb4":"A","\u1eb2":"A","\u0226":"A","\u01e0":"A","\xc4":"A","\u01de":"A","\u1ea2":"A","\xc5":"A","\u01fa":"A","\u01cd":"A","\u0200":"A","\u0202":"A","\u1ea0":"A","\u1eac":"A","\u1eb6":"A","\u1e00":"A","\u0104":"A","\u023a":"A","\u2c6f":"A","\ua732":"AA","\xc6":"AE","\u01fc":"AE","\u01e2":"AE","\ua734":"AO","\ua736":"AU","\ua738":"AV","\ua73a":"AV","\ua73c":"AY","\u24b7":"B","\uff22":"B","\u1e02":"B","\u1e04":"B","\u1e06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24b8":"C","\uff23":"C","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\xc7":"C","\u1e08":"C","\u0187":"C","\u023b":"C","\ua73e":"C","\u24b9":"D","\uff24":"D","\u1e0a":"D","\u010e":"D","\u1e0c":"D","\u1e10":"D","\u1e12":"D","\u1e0e":"D","\u0110":"D","\u018b":"D","\u018a":"D","\u0189":"D","\ua779":"D","\u01f1":"DZ","\u01c4":"DZ","\u01f2":"Dz","\u01c5":"Dz","\u24ba":"E","\uff25":"E","\xc8":"E","\xc9":"E","\xca":"E","\u1ec0":"E","\u1ebe":"E","\u1ec4":"E","\u1ec2":"E","\u1ebc":"E","\u0112":"E","\u1e14":"E","\u1e16":"E","\u0114":"E","\u0116":"E","\xcb":"E","\u1eba":"E","\u011a":"E","\u0204":"E","\u0206":"E","\u1eb8":"E","\u1ec6":"E","\u0228":"E","\u1e1c":"E","\u0118":"E","\u1e18":"E","\u1e1a":"E","\u0190":"E","\u018e":"E","\u24bb":"F","\uff26":"F","\u1e1e":"F","\u0191":"F","\ua77b":"F","\u24bc":"G","\uff27":"G","\u01f4":"G","\u011c":"G","\u1e20":"G","\u011e":"G","\u0120":"G","\u01e6":"G","\u0122":"G","\u01e4":"G","\u0193":"G","\ua7a0":"G","\ua77d":"G","\ua77e":"G","\u24bd":"H","\uff28":"H","\u0124":"H","\u1e22":"H","\u1e26":"H","\u021e":"H","\u1e24":"H","\u1e28":"H","\u1e2a":"H","\u0126":"H","\u2c67":"H","\u2c75":"H","\ua78d":"H","\u24be":"I","\uff29":"I","\xcc":"I","\xcd":"I","\xce":"I","\u0128":"I","\u012a":"I","\u012c":"I","\u0130":"I","\xcf":"I","\u1e2e":"I","\u1ec8":"I","\u01cf":"I","\u0208":"I","\u020a":"I","\u1eca":"I","\u012e":"I","\u1e2c":"I","\u0197":"I","\u24bf":"J","\uff2a":"J","\u0134":"J","\u0248":"J","\u24c0":"K","\uff2b":"K","\u1e30":"K","\u01e8":"K","\u1e32":"K","\u0136":"K","\u1e34":"K","\u0198":"K","\u2c69":"K","\ua740":"K","\ua742":"K","\ua744":"K","\ua7a2":"K","\u24c1":"L","\uff2c":"L","\u013f":"L","\u0139":"L","\u013d":"L","\u1e36":"L","\u1e38":"L","\u013b":"L","\u1e3c":"L","\u1e3a":"L","\u0141":"L","\u023d":"L","\u2c62":"L","\u2c60":"L","\ua748":"L","\ua746":"L","\ua780":"L","\u01c7":"LJ","\u01c8":"Lj","\u24c2":"M","\uff2d":"M","\u1e3e":"M","\u1e40":"M","\u1e42":"M","\u2c6e":"M","\u019c":"M","\u24c3":"N","\uff2e":"N","\u01f8":"N","\u0143":"N","\xd1":"N","\u1e44":"N","\u0147":"N","\u1e46":"N","\u0145":"N","\u1e4a":"N","\u1e48":"N","\u0220":"N","\u019d":"N","\ua790":"N","\ua7a4":"N","\u01ca":"NJ","\u01cb":"Nj","\u24c4":"O","\uff2f":"O","\xd2":"O","\xd3":"O","\xd4":"O","\u1ed2":"O","\u1ed0":"O","\u1ed6":"O","\u1ed4":"O","\xd5":"O","\u1e4c":"O","\u022c":"O","\u1e4e":"O","\u014c":"O","\u1e50":"O","\u1e52":"O","\u014e":"O","\u022e":"O","\u0230":"O","\xd6":"O","\u022a":"O","\u1ece":"O","\u0150":"O","\u01d1":"O","\u020c":"O","\u020e":"O","\u01a0":"O","\u1edc":"O","\u1eda":"O","\u1ee0":"O","\u1ede":"O","\u1ee2":"O","\u1ecc":"O","\u1ed8":"O","\u01ea":"O","\u01ec":"O","\xd8":"O","\u01fe":"O","\u0186":"O","\u019f":"O","\ua74a":"O","\ua74c":"O","\u01a2":"OI","\ua74e":"OO","\u0222":"OU","\u24c5":"P","\uff30":"P","\u1e54":"P","\u1e56":"P","\u01a4":"P","\u2c63":"P","\ua750":"P","\ua752":"P","\ua754":"P","\u24c6":"Q","\uff31":"Q","\ua756":"Q","\ua758":"Q","\u024a":"Q","\u24c7":"R","\uff32":"R","\u0154":"R","\u1e58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1e5a":"R","\u1e5c":"R","\u0156":"R","\u1e5e":"R","\u024c":"R","\u2c64":"R","\ua75a":"R","\ua7a6":"R","\ua782":"R","\u24c8":"S","\uff33":"S","\u1e9e":"S","\u015a":"S","\u1e64":"S","\u015c":"S","\u1e60":"S","\u0160":"S","\u1e66":"S","\u1e62":"S","\u1e68":"S","\u0218":"S","\u015e":"S","\u2c7e":"S","\ua7a8":"S","\ua784":"S","\u24c9":"T","\uff34":"T","\u1e6a":"T","\u0164":"T","\u1e6c":"T","\u021a":"T","\u0162":"T","\u1e70":"T","\u1e6e":"T","\u0166":"T","\u01ac":"T","\u01ae":"T","\u023e":"T","\ua786":"T","\ua728":"TZ","\u24ca":"U","\uff35":"U","\xd9":"U","\xda":"U","\xdb":"U","\u0168":"U","\u1e78":"U","\u016a":"U","\u1e7a":"U","\u016c":"U","\xdc":"U","\u01db":"U","\u01d7":"U","\u01d5":"U","\u01d9":"U","\u1ee6":"U","\u016e":"U","\u0170":"U","\u01d3":"U","\u0214":"U","\u0216":"U","\u01af":"U","\u1eea":"U","\u1ee8":"U","\u1eee":"U","\u1eec":"U","\u1ef0":"U","\u1ee4":"U","\u1e72":"U","\u0172":"U","\u1e76":"U","\u1e74":"U","\u0244":"U","\u24cb":"V","\uff36":"V","\u1e7c":"V","\u1e7e":"V","\u01b2":"V","\ua75e":"V","\u0245":"V","\ua760":"VY","\u24cc":"W","\uff37":"W","\u1e80":"W","\u1e82":"W","\u0174":"W","\u1e86":"W","\u1e84":"W","\u1e88":"W","\u2c72":"W","\u24cd":"X","\uff38":"X","\u1e8a":"X","\u1e8c":"X","\u24ce":"Y","\uff39":"Y","\u1ef2":"Y","\xdd":"Y","\u0176":"Y","\u1ef8":"Y","\u0232":"Y","\u1e8e":"Y","\u0178":"Y","\u1ef6":"Y","\u1ef4":"Y","\u01b3":"Y","\u024e":"Y","\u1efe":"Y","\u24cf":"Z","\uff3a":"Z","\u0179":"Z","\u1e90":"Z","\u017b":"Z","\u017d":"Z","\u1e92":"Z","\u1e94":"Z","\u01b5":"Z","\u0224":"Z","\u2c7f":"Z","\u2c6b":"Z","\ua762":"Z","\u24d0":"a","\uff41":"a","\u1e9a":"a","\xe0":"a","\xe1":"a","\xe2":"a","\u1ea7":"a","\u1ea5":"a","\u1eab":"a","\u1ea9":"a","\xe3":"a","\u0101":"a","\u0103":"a","\u1eb1":"a","\u1eaf":"a","\u1eb5":"a","\u1eb3":"a","\u0227":"a","\u01e1":"a","\xe4":"a","\u01df":"a","\u1ea3":"a","\xe5":"a","\u01fb":"a","\u01ce":"a","\u0201":"a","\u0203":"a","\u1ea1":"a","\u1ead":"a","\u1eb7":"a","\u1e01":"a","\u0105":"a","\u2c65":"a","\u0250":"a","\ua733":"aa","\xe6":"ae","\u01fd":"ae","\u01e3":"ae","\ua735":"ao","\ua737":"au","\ua739":"av","\ua73b":"av","\ua73d":"ay","\u24d1":"b","\uff42":"b","\u1e03":"b","\u1e05":"b","\u1e07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24d2":"c","\uff43":"c","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\xe7":"c","\u1e09":"c","\u0188":"c","\u023c":"c","\ua73f":"c","\u2184":"c","\u24d3":"d","\uff44":"d","\u1e0b":"d","\u010f":"d","\u1e0d":"d","\u1e11":"d","\u1e13":"d","\u1e0f":"d","\u0111":"d","\u018c":"d","\u0256":"d","\u0257":"d","\ua77a":"d","\u01f3":"dz","\u01c6":"dz","\u24d4":"e","\uff45":"e","\xe8":"e","\xe9":"e","\xea":"e","\u1ec1":"e","\u1ebf":"e","\u1ec5":"e","\u1ec3":"e","\u1ebd":"e","\u0113":"e","\u1e15":"e","\u1e17":"e","\u0115":"e","\u0117":"e","\xeb":"e","\u1ebb":"e","\u011b":"e","\u0205":"e","\u0207":"e","\u1eb9":"e","\u1ec7":"e","\u0229":"e","\u1e1d":"e","\u0119":"e","\u1e19":"e","\u1e1b":"e","\u0247":"e","\u025b":"e","\u01dd":"e","\u24d5":"f","\uff46":"f","\u1e1f":"f","\u0192":"f","\ua77c":"f","\u24d6":"g","\uff47":"g","\u01f5":"g","\u011d":"g","\u1e21":"g","\u011f":"g","\u0121":"g","\u01e7":"g","\u0123":"g","\u01e5":"g","\u0260":"g","\ua7a1":"g","\u1d79":"g","\ua77f":"g","\u24d7":"h","\uff48":"h","\u0125":"h","\u1e23":"h","\u1e27":"h","\u021f":"h","\u1e25":"h","\u1e29":"h","\u1e2b":"h","\u1e96":"h","\u0127":"h","\u2c68":"h","\u2c76":"h","\u0265":"h","\u0195":"hv","\u24d8":"i","\uff49":"i","\xec":"i","\xed":"i","\xee":"i","\u0129":"i","\u012b":"i","\u012d":"i","\xef":"i","\u1e2f":"i","\u1ec9":"i","\u01d0":"i","\u0209":"i","\u020b":"i","\u1ecb":"i","\u012f":"i","\u1e2d":"i","\u0268":"i","\u0131":"i","\u24d9":"j","\uff4a":"j","\u0135":"j","\u01f0":"j","\u0249":"j","\u24da":"k","\uff4b":"k","\u1e31":"k","\u01e9":"k","\u1e33":"k","\u0137":"k","\u1e35":"k","\u0199":"k","\u2c6a":"k","\ua741":"k","\ua743":"k","\ua745":"k","\ua7a3":"k","\u24db":"l","\uff4c":"l","\u0140":"l","\u013a":"l","\u013e":"l","\u1e37":"l","\u1e39":"l","\u013c":"l","\u1e3d":"l","\u1e3b":"l","\u017f":"l","\u0142":"l","\u019a":"l","\u026b":"l","\u2c61":"l","\ua749":"l","\ua781":"l","\ua747":"l","\u01c9":"lj","\u24dc":"m","\uff4d":"m","\u1e3f":"m","\u1e41":"m","\u1e43":"m","\u0271":"m","\u026f":"m","\u24dd":"n","\uff4e":"n","\u01f9":"n","\u0144":"n","\xf1":"n","\u1e45":"n","\u0148":"n","\u1e47":"n","\u0146":"n","\u1e4b":"n","\u1e49":"n","\u019e":"n","\u0272":"n","\u0149":"n","\ua791":"n","\ua7a5":"n","\u01cc":"nj","\u24de":"o","\uff4f":"o","\xf2":"o","\xf3":"o","\xf4":"o","\u1ed3":"o","\u1ed1":"o","\u1ed7":"o","\u1ed5":"o","\xf5":"o","\u1e4d":"o","\u022d":"o","\u1e4f":"o","\u014d":"o","\u1e51":"o","\u1e53":"o","\u014f":"o","\u022f":"o","\u0231":"o","\xf6":"o","\u022b":"o","\u1ecf":"o","\u0151":"o","\u01d2":"o","\u020d":"o","\u020f":"o","\u01a1":"o","\u1edd":"o","\u1edb":"o","\u1ee1":"o","\u1edf":"o","\u1ee3":"o","\u1ecd":"o","\u1ed9":"o","\u01eb":"o","\u01ed":"o","\xf8":"o","\u01ff":"o","\u0254":"o","\ua74b":"o","\ua74d":"o","\u0275":"o","\u01a3":"oi","\u0223":"ou","\ua74f":"oo","\u24df":"p","\uff50":"p","\u1e55":"p","\u1e57":"p","\u01a5":"p","\u1d7d":"p","\ua751":"p","\ua753":"p","\ua755":"p","\u24e0":"q","\uff51":"q","\u024b":"q","\ua757":"q","\ua759":"q","\u24e1":"r","\uff52":"r","\u0155":"r","\u1e59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1e5b":"r","\u1e5d":"r","\u0157":"r","\u1e5f":"r","\u024d":"r","\u027d":"r","\ua75b":"r","\ua7a7":"r","\ua783":"r","\u24e2":"s","\uff53":"s","\xdf":"s","\u015b":"s","\u1e65":"s","\u015d":"s","\u1e61":"s","\u0161":"s","\u1e67":"s","\u1e63":"s","\u1e69":"s","\u0219":"s","\u015f":"s","\u023f":"s","\ua7a9":"s","\ua785":"s","\u1e9b":"s","\u24e3":"t","\uff54":"t","\u1e6b":"t","\u1e97":"t","\u0165":"t","\u1e6d":"t","\u021b":"t","\u0163":"t","\u1e71":"t","\u1e6f":"t","\u0167":"t","\u01ad":"t","\u0288":"t","\u2c66":"t","\ua787":"t","\ua729":"tz","\u24e4":"u","\uff55":"u","\xf9":"u","\xfa":"u","\xfb":"u","\u0169":"u","\u1e79":"u","\u016b":"u","\u1e7b":"u","\u016d":"u","\xfc":"u","\u01dc":"u","\u01d8":"u","\u01d6":"u","\u01da":"u","\u1ee7":"u","\u016f":"u","\u0171":"u","\u01d4":"u","\u0215":"u","\u0217":"u","\u01b0":"u","\u1eeb":"u","\u1ee9":"u","\u1eef":"u","\u1eed":"u","\u1ef1":"u","\u1ee5":"u","\u1e73":"u","\u0173":"u","\u1e77":"u","\u1e75":"u","\u0289":"u","\u24e5":"v","\uff56":"v","\u1e7d":"v","\u1e7f":"v","\u028b":"v","\ua75f":"v","\u028c":"v","\ua761":"vy","\u24e6":"w","\uff57":"w","\u1e81":"w","\u1e83":"w","\u0175":"w","\u1e87":"w","\u1e85":"w","\u1e98":"w","\u1e89":"w","\u2c73":"w","\u24e7":"x","\uff58":"x","\u1e8b":"x","\u1e8d":"x","\u24e8":"y","\uff59":"y","\u1ef3":"y","\xfd":"y","\u0177":"y","\u1ef9":"y","\u0233":"y","\u1e8f":"y","\xff":"y","\u1ef7":"y","\u1e99":"y","\u1ef5":"y","\u01b4":"y","\u024f":"y","\u1eff":"y","\u24e9":"z","\uff5a":"z","\u017a":"z","\u1e91":"z","\u017c":"z","\u017e":"z","\u1e93":"z","\u1e95":"z","\u01b6":"z","\u0225":"z","\u0240":"z","\u2c6c":"z","\ua763":"z","\u0386":"\u0391","\u0388":"\u0395","\u0389":"\u0397","\u038a":"\u0399","\u03aa":"\u0399","\u038c":"\u039f","\u038e":"\u03a5","\u03ab":"\u03a5","\u038f":"\u03a9","\u03ac":"\u03b1","\u03ad":"\u03b5","\u03ae":"\u03b7","\u03af":"\u03b9","\u03ca":"\u03b9","\u0390":"\u03b9","\u03cc":"\u03bf","\u03cd":"\u03c5","\u03cb":"\u03c5","\u03b0":"\u03c5","\u03c9":"\u03c9","\u03c2":"\u03c3"};i=a(document),f=function(){var a=1;return function(){return a++}}(),c=O(Object,{bind:function(a){var b=this;return function(){a.apply(b,arguments)}},init:function(c){var d,e,g=".select2-results";this.opts=c=this.prepareOpts(c),this.id=c.id,c.element.data("select2")!==b&&null!==c.element.data("select2")&&c.element.data("select2").destroy(),this.container=this.createContainer(),this.liveRegion=a(".select2-hidden-accessible"),0==this.liveRegion.length&&(this.liveRegion=a("<span>",{role:"status","aria-live":"polite"}).addClass("select2-hidden-accessible").appendTo(document.body)),this.containerId="s2id_"+(c.element.attr("id")||"autogen"+f()),this.containerEventName=this.containerId.replace(/([.])/g,"_").replace(/([;&,\-\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g,"\\$1"),this.container.attr("id",this.containerId),this.container.attr("title",c.element.attr("title")),this.body=a(document.body),D(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.attr("style",c.element.attr("style")),this.container.css(K(c.containerCss,this.opts.element)),this.container.addClass(K(c.containerCssClass,this.opts.element)),this.elementTabIndex=this.opts.element.attr("tabindex"),this.opts.element.data("select2",this).attr("tabindex","-1").before(this.container).on("click.select2",A),this.container.data("select2",this),this.dropdown=this.container.find(".select2-drop"),D(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(K(c.dropdownCssClass,this.opts.element)),this.dropdown.data("select2",this),this.dropdown.on("click",A),this.results=d=this.container.find(g),this.search=e=this.container.find("input.select2-input"),this.queryCount=0,this.resultsPage=0,this.context=null,this.initContainer(),this.container.on("click",A),v(this.results),this.dropdown.on("mousemove-filtered",g,this.bind(this.highlightUnderEvent)),this.dropdown.on("touchstart touchmove touchend",g,this.bind(function(a){this._touchEvent=!0,this.highlightUnderEvent(a)})),this.dropdown.on("touchmove",g,this.bind(this.touchMoved)),this.dropdown.on("touchstart touchend",g,this.bind(this.clearTouchMoved)),this.dropdown.on("click",this.bind(function(){this._touchEvent&&(this._touchEvent=!1,this.selectHighlighted())})),x(80,this.results),this.dropdown.on("scroll-debounced",g,this.bind(this.loadMoreIfNeeded)),a(this.container).on("change",".select2-input",function(a){a.stopPropagation()}),a(this.dropdown).on("change",".select2-input",function(a){a.stopPropagation()}),a.fn.mousewheel&&d.mousewheel(function(a,b,c,e){var f=d.scrollTop();e>0&&0>=f-e?(d.scrollTop(0),A(a)):0>e&&d.get(0).scrollHeight-d.scrollTop()+e<=d.height()&&(d.scrollTop(d.get(0).scrollHeight-d.height()),A(a))}),u(e),e.on("keyup-change input paste",this.bind(this.updateResults)),e.on("focus",function(){e.addClass("select2-focused")}),e.on("blur",function(){e.removeClass("select2-focused")}),this.dropdown.on("mouseup",g,this.bind(function(b){a(b.target).closest(".select2-result-selectable").length>0&&(this.highlightUnderEvent(b),this.selectHighlighted(b))})),this.dropdown.on("click mouseup mousedown touchstart touchend focusin",function(a){a.stopPropagation()}),this.nextSearchTerm=b,a.isFunction(this.opts.initSelection)&&(this.initSelection(),this.monitorSource()),null!==c.maximumInputLength&&this.search.attr("maxlength",c.maximumInputLength);var h=c.element.prop("disabled");h===b&&(h=!1),this.enable(!h);var i=c.element.prop("readonly");i===b&&(i=!1),this.readonly(i),j=j||q(),this.autofocus=c.element.prop("autofocus"),c.element.prop("autofocus",!1),this.autofocus&&this.focus(),this.search.attr("placeholder",c.searchInputPlaceholder)},destroy:function(){var a=this.opts.element,c=a.data("select2"),d=this;this.close(),a.length&&a[0].detachEvent&&d._sync&&a.each(function(){d._sync&&this.detachEvent("onpropertychange",d._sync)}),this.propertyObserver&&(this.propertyObserver.disconnect(),this.propertyObserver=null),this._sync=null,c!==b&&(c.container.remove(),c.liveRegion.remove(),c.dropdown.remove(),a.show().removeData("select2").off(".select2").prop("autofocus",this.autofocus||!1),this.elementTabIndex?a.attr({tabindex:this.elementTabIndex}):a.removeAttr("tabindex"),a.show()),N.call(this,"container","liveRegion","dropdown","results","search")},optionToData:function(a){return a.is("option")?{id:a.prop("value"),text:a.text(),element:a.get(),css:a.attr("class"),disabled:a.prop("disabled"),locked:r(a.attr("locked"),"locked")||r(a.data("locked"),!0)}:a.is("optgroup")?{text:a.attr("label"),children:[],element:a.get(),css:a.attr("class")}:void 0},prepareOpts:function(c){var d,e,g,h,i=this;if(d=c.element,"select"===d.get(0).tagName.toLowerCase()&&(this.select=e=c.element),e&&a.each(["id","multiple","ajax","query","createSearchChoice","initSelection","data","tags"],function(){if(this in c)throw new Error("Option '"+this+"' is not allowed for Select2 when attached to a <select> element.")}),c=a.extend({},{populateResults:function(d,e,g){var h,j=this.opts.id,k=this.liveRegion;h=function(d,e,l){var m,n,o,p,q,r,s,t,u,v;d=c.sortResults(d,e,g);var w=[];for(m=0,n=d.length;n>m;m+=1)o=d[m],q=o.disabled===!0,p=!q&&j(o)!==b,r=o.children&&o.children.length>0,s=a("<li></li>"),s.addClass("select2-results-dept-"+l),s.addClass("select2-result"),s.addClass(p?"select2-result-selectable":"select2-result-unselectable"),q&&s.addClass("select2-disabled"),r&&s.addClass("select2-result-with-children"),s.addClass(i.opts.formatResultCssClass(o)),s.attr("role","presentation"),t=a(document.createElement("div")),t.addClass("select2-result-label"),t.attr("id","select2-result-label-"+f()),t.attr("role","option"),v=c.formatResult(o,t,g,i.opts.escapeMarkup),v!==b&&(t.html(v),s.append(t)),r&&(u=a("<ul></ul>"),u.addClass("select2-result-sub"),h(o.children,u,l+1),s.append(u)),s.data("select2-data",o),w.push(s[0]);e.append(w),k.text(c.formatMatches(d.length))},h(e,d,0)}},a.fn.select2.defaults,c),"function"!=typeof c.id&&(g=c.id,c.id=function(a){return a[g]}),a.isArray(c.element.data("select2Tags"))){if("tags"in c)throw"tags specified as both an attribute 'data-select2-tags' and in options of Select2 "+c.element.attr("id");c.tags=c.element.data("select2Tags")}if(e?(c.query=this.bind(function(a){var f,g,h,c={results:[],more:!1},e=a.term;h=function(b,c){var d;b.is("option")?a.matcher(e,b.text(),b)&&c.push(i.optionToData(b)):b.is("optgroup")&&(d=i.optionToData(b),b.children().each2(function(a,b){h(b,d.children)}),d.children.length>0&&c.push(d))},f=d.children(),this.getPlaceholder()!==b&&f.length>0&&(g=this.getPlaceholderOption(),g&&(f=f.not(g))),f.each2(function(a,b){h(b,c.results)}),a.callback(c)}),c.id=function(a){return a.id}):"query"in c||("ajax"in c?(h=c.element.data("ajax-url"),h&&h.length>0&&(c.ajax.url=h),c.query=G.call(c.element,c.ajax)):"data"in c?c.query=H(c.data):"tags"in c&&(c.query=I(c.tags),c.createSearchChoice===b&&(c.createSearchChoice=function(b){return{id:a.trim(b),text:a.trim(b)}}),c.initSelection===b&&(c.initSelection=function(b,d){var e=[];a(s(b.val(),c.separator,c.transformVal)).each(function(){var b={id:this,text:this},d=c.tags;a.isFunction(d)&&(d=d()),a(d).each(function(){return r(this.id,b.id)?(b=this,!1):void 0}),e.push(b)}),d(e)}))),"function"!=typeof c.query)throw"query function not defined for Select2 "+c.element.attr("id");if("top"===c.createSearchChoicePosition)c.createSearchChoicePosition=function(a,b){a.unshift(b)};else if("bottom"===c.createSearchChoicePosition)c.createSearchChoicePosition=function(a,b){a.push(b)};else if("function"!=typeof c.createSearchChoicePosition)throw"invalid createSearchChoicePosition option must be 'top', 'bottom' or a custom function";return c},monitorSource:function(){var d,c=this.opts.element,e=this;c.on("change.select2",this.bind(function(){this.opts.element.data("select2-change-triggered")!==!0&&this.initSelection()})),this._sync=this.bind(function(){var a=c.prop("disabled");a===b&&(a=!1),this.enable(!a);var d=c.prop("readonly");d===b&&(d=!1),this.readonly(d),this.container&&(D(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.addClass(K(this.opts.containerCssClass,this.opts.element))),this.dropdown&&(D(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(K(this.opts.dropdownCssClass,this.opts.element)))}),c.length&&c[0].attachEvent&&c.each(function(){this.attachEvent("onpropertychange",e._sync)}),d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver,d!==b&&(this.propertyObserver&&(delete this.propertyObserver,this.propertyObserver=null),this.propertyObserver=new d(function(b){a.each(b,e._sync)}),this.propertyObserver.observe(c.get(0),{attributes:!0,subtree:!1}))},triggerSelect:function(b){var c=a.Event("select2-selecting",{val:this.id(b),object:b,choice:b});return this.opts.element.trigger(c),!c.isDefaultPrevented()},triggerChange:function(b){b=b||{},b=a.extend({},b,{type:"change",val:this.val()}),this.opts.element.data("select2-change-triggered",!0),this.opts.element.trigger(b),this.opts.element.data("select2-change-triggered",!1),this.opts.element.click(),this.opts.blurOnChange&&this.opts.element.blur()},isInterfaceEnabled:function(){return this.enabledInterface===!0},enableInterface:function(){var a=this._enabled&&!this._readonly,b=!a;return a===this.enabledInterface?!1:(this.container.toggleClass("select2-container-disabled",b),this.close(),this.enabledInterface=a,!0)},enable:function(a){a===b&&(a=!0),this._enabled!==a&&(this._enabled=a,this.opts.element.prop("disabled",!a),this.enableInterface())},disable:function(){this.enable(!1)},readonly:function(a){a===b&&(a=!1),this._readonly!==a&&(this._readonly=a,this.opts.element.prop("readonly",a),this.enableInterface())},opened:function(){return this.container?this.container.hasClass("select2-dropdown-open"):!1},positionDropdown:function(){var v,w,x,y,z,b=this.dropdown,c=this.container,d=c.offset(),e=c.outerHeight(!1),f=c.outerWidth(!1),g=b.outerHeight(!1),h=a(window),i=h.width(),k=h.height(),l=h.scrollLeft()+i,m=h.scrollTop()+k,n=d.top+e,o=d.left,p=m>=n+g,q=d.top-g>=h.scrollTop(),r=b.outerWidth(!1),s=function(){return l>=o+r},t=function(){return d.left+l+c.outerWidth(!1)>r},u=b.hasClass("select2-drop-above");u?(w=!0,!q&&p&&(x=!0,w=!1)):(w=!1,!p&&q&&(x=!0,w=!0)),x&&(b.hide(),d=this.container.offset(),e=this.container.outerHeight(!1),f=this.container.outerWidth(!1),g=b.outerHeight(!1),l=h.scrollLeft()+i,m=h.scrollTop()+k,n=d.top+e,o=d.left,r=b.outerWidth(!1),b.show(),this.focusSearch()),this.opts.dropdownAutoWidth?(z=a(".select2-results",b)[0],b.addClass("select2-drop-auto-width"),b.css("width",""),r=b.outerWidth(!1)+(z.scrollHeight===z.clientHeight?0:j.width),r>f?f=r:r=f,g=b.outerHeight(!1)):this.container.removeClass("select2-drop-auto-width"),"static"!==this.body.css("position")&&(v=this.body.offset(),n-=v.top,o-=v.left),!s()&&t()&&(o=d.left+this.container.outerWidth(!1)-r),y={left:o,width:f},w?(y.top=d.top-g,y.bottom="auto",this.container.addClass("select2-drop-above"),b.addClass("select2-drop-above")):(y.top=n,y.bottom="auto",this.container.removeClass("select2-drop-above"),b.removeClass("select2-drop-above")),y=a.extend(y,K(this.opts.dropdownCss,this.opts.element)),b.css(y)},shouldOpen:function(){var b;return this.opened()?!1:this._enabled===!1||this._readonly===!0?!1:(b=a.Event("select2-opening"),this.opts.element.trigger(b),!b.isDefaultPrevented())},clearDropdownAlignmentPreference:function(){this.container.removeClass("select2-drop-above"),this.dropdown.removeClass("select2-drop-above")},open:function(){return this.shouldOpen()?(this.opening(),i.on("mousemove.select2Event",function(a){h.x=a.pageX,h.y=a.pageY}),!0):!1},opening:function(){var f,b=this.containerEventName,c="scroll."+b,d="resize."+b,e="orientationchange."+b;this.container.addClass("select2-dropdown-open").addClass("select2-container-active"),this.clearDropdownAlignmentPreference(),this.dropdown[0]!==this.body.children().last()[0]&&this.dropdown.detach().appendTo(this.body),f=a("#select2-drop-mask"),0===f.length&&(f=a(document.createElement("div")),f.attr("id","select2-drop-mask").attr("class","select2-drop-mask"),f.hide(),f.appendTo(this.body),f.on("mousedown touchstart click",function(b){n(f);var d,c=a("#select2-drop");c.length>0&&(d=c.data("select2"),d.opts.selectOnBlur&&d.selectHighlighted({noFocus:!0}),d.close(),b.preventDefault(),b.stopPropagation())})),this.dropdown.prev()[0]!==f[0]&&this.dropdown.before(f),a("#select2-drop").removeAttr("id"),this.dropdown.attr("id","select2-drop"),f.show(),this.positionDropdown(),this.dropdown.show(),this.positionDropdown(),this.dropdown.addClass("select2-drop-active");var g=this;this.container.parents().add(window).each(function(){a(this).on(d+" "+c+" "+e,function(){g.opened()&&g.positionDropdown()})})},close:function(){if(this.opened()){var b=this.containerEventName,c="scroll."+b,d="resize."+b,e="orientationchange."+b;this.container.parents().add(window).each(function(){a(this).off(c).off(d).off(e)}),this.clearDropdownAlignmentPreference(),a("#select2-drop-mask").hide(),this.dropdown.removeAttr("id"),this.dropdown.hide(),this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active"),this.results.empty(),i.off("mousemove.select2Event"),this.clearSearch(),this.search.removeClass("select2-active"),this.opts.element.trigger(a.Event("select2-close"))}},externalSearch:function(a){this.open(),this.search.val(a),this.updateResults(!1)},clearSearch:function(){},getMaximumSelectionSize:function(){return K(this.opts.maximumSelectionSize,this.opts.element)},ensureHighlightVisible:function(){var c,d,e,f,g,h,i,j,b=this.results;if(d=this.highlight(),!(0>d)){if(0==d)return b.scrollTop(0),void 0;c=this.findHighlightableChoices().find(".select2-result-label"),e=a(c[d]),j=(e.offset()||{}).top||0,f=j+e.outerHeight(!0),d===c.length-1&&(i=b.find("li.select2-more-results"),i.length>0&&(f=i.offset().top+i.outerHeight(!0))),g=b.offset().top+b.outerHeight(!1),f>g&&b.scrollTop(b.scrollTop()+(f-g)),h=j-b.offset().top,0>h&&"none"!=e.css("display")&&b.scrollTop(b.scrollTop()+h)}},findHighlightableChoices:function(){return this.results.find(".select2-result-selectable:not(.select2-disabled):not(.select2-selected)")},moveHighlight:function(b){for(var c=this.findHighlightableChoices(),d=this.highlight();d>-1&&d<c.length;){d+=b;
22
+ var e=a(c[d]);if(e.hasClass("select2-result-selectable")&&!e.hasClass("select2-disabled")&&!e.hasClass("select2-selected")){this.highlight(d);break}}},highlight:function(b){var d,e,c=this.findHighlightableChoices();return 0===arguments.length?p(c.filter(".select2-highlighted")[0],c.get()):(b>=c.length&&(b=c.length-1),0>b&&(b=0),this.removeHighlight(),d=a(c[b]),d.addClass("select2-highlighted"),this.search.attr("aria-activedescendant",d.find(".select2-result-label").attr("id")),this.ensureHighlightVisible(),this.liveRegion.text(d.text()),e=d.data("select2-data"),e&&this.opts.element.trigger({type:"select2-highlight",val:this.id(e),choice:e}),void 0)},removeHighlight:function(){this.results.find(".select2-highlighted").removeClass("select2-highlighted")},touchMoved:function(){this._touchMoved=!0},clearTouchMoved:function(){this._touchMoved=!1},countSelectableResults:function(){return this.findHighlightableChoices().length},highlightUnderEvent:function(b){var c=a(b.target).closest(".select2-result-selectable");if(c.length>0&&!c.is(".select2-highlighted")){var d=this.findHighlightableChoices();this.highlight(d.index(c))}else 0==c.length&&this.removeHighlight()},loadMoreIfNeeded:function(){var c,a=this.results,b=a.find("li.select2-more-results"),d=this.resultsPage+1,e=this,f=this.search.val(),g=this.context;0!==b.length&&(c=b.offset().top-a.offset().top-a.height(),c<=this.opts.loadMorePadding&&(b.addClass("select2-active"),this.opts.query({element:this.opts.element,term:f,page:d,context:g,matcher:this.opts.matcher,callback:this.bind(function(c){e.opened()&&(e.opts.populateResults.call(this,a,c.results,{term:f,page:d,context:g}),e.postprocessResults(c,!1,!1),c.more===!0?(b.detach().appendTo(a).html(e.opts.escapeMarkup(K(e.opts.formatLoadMore,e.opts.element,d+1))),window.setTimeout(function(){e.loadMoreIfNeeded()},10)):b.remove(),e.positionDropdown(),e.resultsPage=d,e.context=c.context,this.opts.element.trigger({type:"select2-loaded",items:c}))})})))},tokenize:function(){},updateResults:function(c){function m(){d.removeClass("select2-active"),h.positionDropdown(),e.find(".select2-no-results,.select2-selection-limit,.select2-searching").length?h.liveRegion.text(e.text()):h.liveRegion.text(h.opts.formatMatches(e.find('.select2-result-selectable:not(".select2-selected")').length))}function n(a){e.html(a),m()}var g,i,l,d=this.search,e=this.results,f=this.opts,h=this,j=d.val(),k=a.data(this.container,"select2-last-term");if((c===!0||!k||!r(j,k))&&(a.data(this.container,"select2-last-term",j),c===!0||this.showSearchInput!==!1&&this.opened())){l=++this.queryCount;var o=this.getMaximumSelectionSize();if(o>=1&&(g=this.data(),a.isArray(g)&&g.length>=o&&J(f.formatSelectionTooBig,"formatSelectionTooBig")))return n("<li class='select2-selection-limit'>"+K(f.formatSelectionTooBig,f.element,o)+"</li>"),void 0;if(d.val().length<f.minimumInputLength)return J(f.formatInputTooShort,"formatInputTooShort")?n("<li class='select2-no-results'>"+K(f.formatInputTooShort,f.element,d.val(),f.minimumInputLength)+"</li>"):n(""),c&&this.showSearch&&this.showSearch(!0),void 0;if(f.maximumInputLength&&d.val().length>f.maximumInputLength)return J(f.formatInputTooLong,"formatInputTooLong")?n("<li class='select2-no-results'>"+K(f.formatInputTooLong,f.element,d.val(),f.maximumInputLength)+"</li>"):n(""),void 0;f.formatSearching&&0===this.findHighlightableChoices().length&&n("<li class='select2-searching'>"+K(f.formatSearching,f.element)+"</li>"),d.addClass("select2-active"),this.removeHighlight(),i=this.tokenize(),i!=b&&null!=i&&d.val(i),this.resultsPage=1,f.query({element:f.element,term:d.val(),page:this.resultsPage,context:null,matcher:f.matcher,callback:this.bind(function(g){var i;if(l==this.queryCount){if(!this.opened())return this.search.removeClass("select2-active"),void 0;if(g.hasError!==b&&J(f.formatAjaxError,"formatAjaxError"))return n("<li class='select2-ajax-error'>"+K(f.formatAjaxError,f.element,g.jqXHR,g.textStatus,g.errorThrown)+"</li>"),void 0;if(this.context=g.context===b?null:g.context,this.opts.createSearchChoice&&""!==d.val()&&(i=this.opts.createSearchChoice.call(h,d.val(),g.results),i!==b&&null!==i&&h.id(i)!==b&&null!==h.id(i)&&0===a(g.results).filter(function(){return r(h.id(this),h.id(i))}).length&&this.opts.createSearchChoicePosition(g.results,i)),0===g.results.length&&J(f.formatNoMatches,"formatNoMatches"))return n("<li class='select2-no-results'>"+K(f.formatNoMatches,f.element,d.val())+"</li>"),void 0;e.empty(),h.opts.populateResults.call(this,e,g.results,{term:d.val(),page:this.resultsPage,context:null}),g.more===!0&&J(f.formatLoadMore,"formatLoadMore")&&(e.append("<li class='select2-more-results'>"+f.escapeMarkup(K(f.formatLoadMore,f.element,this.resultsPage))+"</li>"),window.setTimeout(function(){h.loadMoreIfNeeded()},10)),this.postprocessResults(g,c),m(),this.opts.element.trigger({type:"select2-loaded",items:g})}})})}},cancel:function(){this.close()},blur:function(){this.opts.selectOnBlur&&this.selectHighlighted({noFocus:!0}),this.close(),this.container.removeClass("select2-container-active"),this.search[0]===document.activeElement&&this.search.blur(),this.clearSearch(),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus")},focusSearch:function(){y(this.search)},selectHighlighted:function(a){if(this._touchMoved)return this.clearTouchMoved(),void 0;var b=this.highlight(),c=this.results.find(".select2-highlighted"),d=c.closest(".select2-result").data("select2-data");d?(this.highlight(b),this.onSelect(d,a)):a&&a.noFocus&&this.close()},getPlaceholder:function(){var a;return this.opts.element.attr("placeholder")||this.opts.element.attr("data-placeholder")||this.opts.element.data("placeholder")||this.opts.placeholder||((a=this.getPlaceholderOption())!==b?a.text():b)},getPlaceholderOption:function(){if(this.select){var c=this.select.children("option").first();if(this.opts.placeholderOption!==b)return"first"===this.opts.placeholderOption&&c||"function"==typeof this.opts.placeholderOption&&this.opts.placeholderOption(this.select);if(""===a.trim(c.text())&&""===c.val())return c}},initContainerWidth:function(){function c(){var c,d,e,f,g,h;if("off"===this.opts.width)return null;if("element"===this.opts.width)return 0===this.opts.element.outerWidth(!1)?"auto":this.opts.element.outerWidth(!1)+"px";if("copy"===this.opts.width||"resolve"===this.opts.width){if(c=this.opts.element.attr("style"),c!==b)for(d=c.split(";"),f=0,g=d.length;g>f;f+=1)if(h=d[f].replace(/\s/g,""),e=h.match(/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i),null!==e&&e.length>=1)return e[1];return"resolve"===this.opts.width?(c=this.opts.element.css("width"),c.indexOf("%")>0?c:0===this.opts.element.outerWidth(!1)?"auto":this.opts.element.outerWidth(!1)+"px"):null}return a.isFunction(this.opts.width)?this.opts.width():this.opts.width}var d=c.call(this);null!==d&&this.container.css("width",d)}}),d=O(c,{createContainer:function(){var b=a(document.createElement("div")).attr({"class":"select2-container"}).html(["<a href='javascript:void(0)' class='select2-choice' tabindex='-1'>"," <span class='select2-chosen'>&#160;</span><abbr class='select2-search-choice-close'></abbr>"," <span class='select2-arrow' role='presentation'><b role='presentation'></b></span>","</a>","<label for='' class='select2-offscreen'></label>","<input class='select2-focusser select2-offscreen' type='text' aria-haspopup='true' role='button' />","<div class='select2-drop select2-display-none'>"," <div class='select2-search'>"," <label for='' class='select2-offscreen'></label>"," <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input' role='combobox' aria-expanded='true'"," aria-autocomplete='list' />"," </div>"," <ul class='select2-results' role='listbox'>"," </ul>","</div>"].join(""));return b},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.focusser.prop("disabled",!this.isInterfaceEnabled())},opening:function(){var c,d,e;this.opts.minimumResultsForSearch>=0&&this.showSearch(!0),this.parent.opening.apply(this,arguments),this.showSearchInput!==!1&&this.search.val(this.focusser.val()),this.opts.shouldFocusInput(this)&&(this.search.focus(),c=this.search.get(0),c.createTextRange?(d=c.createTextRange(),d.collapse(!1),d.select()):c.setSelectionRange&&(e=this.search.val().length,c.setSelectionRange(e,e))),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.focusser.prop("disabled",!0).val(""),this.updateResults(!0),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&(this.parent.close.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},focus:function(){this.opened()?this.close():(this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},isFocused:function(){return this.container.hasClass("select2-container-active")},cancel:function(){this.parent.cancel.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus()},destroy:function(){a("label[for='"+this.focusser.attr("id")+"']").attr("for",this.opts.element.attr("id")),this.parent.destroy.apply(this,arguments),N.call(this,"selection","focusser")},initContainer:function(){var b,g,c=this.container,d=this.dropdown,e=f();this.opts.minimumResultsForSearch<0?this.showSearch(!1):this.showSearch(!0),this.selection=b=c.find(".select2-choice"),this.focusser=c.find(".select2-focusser"),b.find(".select2-chosen").attr("id","select2-chosen-"+e),this.focusser.attr("aria-labelledby","select2-chosen-"+e),this.results.attr("id","select2-results-"+e),this.search.attr("aria-owns","select2-results-"+e),this.focusser.attr("id","s2id_autogen"+e),g=a("label[for='"+this.opts.element.attr("id")+"']"),this.opts.element.focus(this.bind(function(){this.focus()})),this.focusser.prev().text(g.text()).attr("for",this.focusser.attr("id"));var h=this.opts.element.attr("title");this.opts.element.attr("title",h||g.text()),this.focusser.attr("tabindex",this.elementTabIndex),this.search.attr("id",this.focusser.attr("id")+"_search"),this.search.prev().text(a("label[for='"+this.focusser.attr("id")+"']").text()).attr("for",this.search.attr("id")),this.search.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()&&229!=a.keyCode){if(a.which===k.PAGE_UP||a.which===k.PAGE_DOWN)return A(a),void 0;switch(a.which){case k.UP:case k.DOWN:return this.moveHighlight(a.which===k.UP?-1:1),A(a),void 0;case k.ENTER:return this.selectHighlighted(),A(a),void 0;case k.TAB:return this.selectHighlighted({noFocus:!0}),void 0;case k.ESC:return this.cancel(a),A(a),void 0}}})),this.search.on("blur",this.bind(function(){document.activeElement===this.body.get(0)&&window.setTimeout(this.bind(function(){this.opened()&&this.search.focus()}),0)})),this.focusser.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()&&a.which!==k.TAB&&!k.isControl(a)&&!k.isFunctionKey(a)&&a.which!==k.ESC){if(this.opts.openOnEnter===!1&&a.which===k.ENTER)return A(a),void 0;if(a.which==k.DOWN||a.which==k.UP||a.which==k.ENTER&&this.opts.openOnEnter){if(a.altKey||a.ctrlKey||a.shiftKey||a.metaKey)return;return this.open(),A(a),void 0}return a.which==k.DELETE||a.which==k.BACKSPACE?(this.opts.allowClear&&this.clear(),A(a),void 0):void 0}})),u(this.focusser),this.focusser.on("keyup-change input",this.bind(function(a){if(this.opts.minimumResultsForSearch>=0){if(a.stopPropagation(),this.opened())return;this.open()}})),b.on("mousedown touchstart","abbr",this.bind(function(a){this.isInterfaceEnabled()&&(this.clear(),B(a),this.close(),this.selection&&this.selection.focus())})),b.on("mousedown touchstart",this.bind(function(c){n(b),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.opened()?this.close():this.isInterfaceEnabled()&&this.open(),A(c)})),d.on("mousedown touchstart",this.bind(function(){this.opts.shouldFocusInput(this)&&this.search.focus()})),b.on("focus",this.bind(function(a){A(a)})),this.focusser.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})).on("blur",this.bind(function(){this.opened()||(this.container.removeClass("select2-container-active"),this.opts.element.trigger(a.Event("select2-blur")))})),this.search.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})),this.initContainerWidth(),this.opts.element.hide(),this.setPlaceholder()},clear:function(b){var c=this.selection.data("select2-data");if(c){var d=a.Event("select2-clearing");if(this.opts.element.trigger(d),d.isDefaultPrevented())return;var e=this.getPlaceholderOption();this.opts.element.val(e?e.val():""),this.selection.find(".select2-chosen").empty(),this.selection.removeData("select2-data"),this.setPlaceholder(),b!==!1&&(this.opts.element.trigger({type:"select2-removed",val:this.id(c),choice:c}),this.triggerChange({removed:c}))}},initSelection:function(){if(this.isPlaceholderOptionSelected())this.updateSelection(null),this.close(),this.setPlaceholder();else{var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.setPlaceholder(),c.nextSearchTerm=c.opts.nextSearchTerm(a,c.search.val()))})}},isPlaceholderOptionSelected:function(){var a;return this.getPlaceholder()===b?!1:(a=this.getPlaceholderOption())!==b&&a.prop("selected")||""===this.opts.element.val()||this.opts.element.val()===b||null===this.opts.element.val()},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=a.find("option").filter(function(){return this.selected&&!this.disabled});b(c.optionToData(d))}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=c.val(),f=null;b.query({matcher:function(a,c,d){var g=r(e,b.id(d));return g&&(f=d),g},callback:a.isFunction(d)?function(){d(f)}:a.noop})}),b},getPlaceholder:function(){return this.select&&this.getPlaceholderOption()===b?b:this.parent.getPlaceholder.apply(this,arguments)},setPlaceholder:function(){var a=this.getPlaceholder();if(this.isPlaceholderOptionSelected()&&a!==b){if(this.select&&this.getPlaceholderOption()===b)return;this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(a)),this.selection.addClass("select2-default"),this.container.removeClass("select2-allowclear")}},postprocessResults:function(a,b,c){var d=0,e=this;if(this.findHighlightableChoices().each2(function(a,b){return r(e.id(b.data("select2-data")),e.opts.element.val())?(d=a,!1):void 0}),c!==!1&&(b===!0&&d>=0?this.highlight(d):this.highlight(0)),b===!0){var g=this.opts.minimumResultsForSearch;g>=0&&this.showSearch(L(a.results)>=g)}},showSearch:function(b){this.showSearchInput!==b&&(this.showSearchInput=b,this.dropdown.find(".select2-search").toggleClass("select2-search-hidden",!b),this.dropdown.find(".select2-search").toggleClass("select2-offscreen",!b),a(this.dropdown,this.container).toggleClass("select2-with-searchbox",b))},onSelect:function(a,b){if(this.triggerSelect(a)){var c=this.opts.element.val(),d=this.data();this.opts.element.val(this.id(a)),this.updateSelection(a),this.opts.element.trigger({type:"select2-selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.close(),b&&b.noFocus||!this.opts.shouldFocusInput(this)||this.focusser.focus(),r(c,this.id(a))||this.triggerChange({added:a,removed:d})}},updateSelection:function(a){var d,e,c=this.selection.find(".select2-chosen");this.selection.data("select2-data",a),c.empty(),null!==a&&(d=this.opts.formatSelection(a,c,this.opts.escapeMarkup)),d!==b&&c.append(d),e=this.opts.formatSelectionCssClass(a,c),e!==b&&c.addClass(e),this.selection.removeClass("select2-default"),this.opts.allowClear&&this.getPlaceholder()!==b&&this.container.addClass("select2-allowclear")},val:function(){var a,c=!1,d=null,e=this,f=this.data();if(0===arguments.length)return this.opts.element.val();if(a=arguments[0],arguments.length>1&&(c=arguments[1]),this.select)this.select.val(a).find("option").filter(function(){return this.selected}).each2(function(a,b){return d=e.optionToData(b),!1}),this.updateSelection(d),this.setPlaceholder(),c&&this.triggerChange({added:d,removed:f});else{if(!a&&0!==a)return this.clear(c),void 0;if(this.opts.initSelection===b)throw new Error("cannot call val() if initSelection() is not defined");this.opts.element.val(a),this.opts.initSelection(this.opts.element,function(a){e.opts.element.val(a?e.id(a):""),e.updateSelection(a),e.setPlaceholder(),c&&e.triggerChange({added:a,removed:f})})}},clearSearch:function(){this.search.val(""),this.focusser.val("")},data:function(a){var c,d=!1;return 0===arguments.length?(c=this.selection.data("select2-data"),c==b&&(c=null),c):(arguments.length>1&&(d=arguments[1]),a?(c=this.data(),this.opts.element.val(a?this.id(a):""),this.updateSelection(a),d&&this.triggerChange({added:a,removed:c})):this.clear(d),void 0)}}),e=O(c,{createContainer:function(){var b=a(document.createElement("div")).attr({"class":"select2-container select2-container-multi"}).html(["<ul class='select2-choices'>"," <li class='select2-search-field'>"," <label for='' class='select2-offscreen'></label>"," <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>"," </li>","</ul>","<div class='select2-drop select2-drop-multi select2-display-none'>"," <ul class='select2-results'>"," </ul>","</div>"].join(""));return b},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=[];a.find("option").filter(function(){return this.selected&&!this.disabled}).each2(function(a,b){d.push(c.optionToData(b))}),b(d)}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=s(c.val(),b.separator,b.transformVal),f=[];b.query({matcher:function(c,d,g){var h=a.grep(e,function(a){return r(a,b.id(g))}).length;return h&&f.push(g),h},callback:a.isFunction(d)?function(){for(var a=[],c=0;c<e.length;c++)for(var g=e[c],h=0;h<f.length;h++){var i=f[h];if(r(g,b.id(i))){a.push(i),f.splice(h,1);break}}d(a)}:a.noop})}),b},selectChoice:function(a){var b=this.container.find(".select2-search-choice-focus");b.length&&a&&a[0]==b[0]||(b.length&&this.opts.element.trigger("choice-deselected",b),b.removeClass("select2-search-choice-focus"),a&&a.length&&(this.close(),a.addClass("select2-search-choice-focus"),this.opts.element.trigger("choice-selected",a)))},destroy:function(){a("label[for='"+this.search.attr("id")+"']").attr("for",this.opts.element.attr("id")),this.parent.destroy.apply(this,arguments),N.call(this,"searchContainer","selection")},initContainer:function(){var c,b=".select2-choices";this.searchContainer=this.container.find(".select2-search-field"),this.selection=c=this.container.find(b);var d=this;this.selection.on("click",".select2-container:not(.select2-container-disabled) .select2-search-choice:not(.select2-locked)",function(){d.search[0].focus(),d.selectChoice(a(this))}),this.search.attr("id","s2id_autogen"+f()),this.search.prev().text(a("label[for='"+this.opts.element.attr("id")+"']").text()).attr("for",this.search.attr("id")),this.opts.element.focus(this.bind(function(){this.focus()})),this.search.on("input paste",this.bind(function(){this.search.attr("placeholder")&&0==this.search.val().length||this.isInterfaceEnabled()&&(this.opened()||this.open())})),this.search.attr("tabindex",this.elementTabIndex),this.keydowns=0,this.search.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()){++this.keydowns;var b=c.find(".select2-search-choice-focus"),d=b.prev(".select2-search-choice:not(.select2-locked)"),e=b.next(".select2-search-choice:not(.select2-locked)"),f=z(this.search);if(b.length&&(a.which==k.LEFT||a.which==k.RIGHT||a.which==k.BACKSPACE||a.which==k.DELETE||a.which==k.ENTER)){var g=b;return a.which==k.LEFT&&d.length?g=d:a.which==k.RIGHT?g=e.length?e:null:a.which===k.BACKSPACE?this.unselect(b.first())&&(this.search.width(10),g=d.length?d:e):a.which==k.DELETE?this.unselect(b.first())&&(this.search.width(10),g=e.length?e:null):a.which==k.ENTER&&(g=null),this.selectChoice(g),A(a),g&&g.length||this.open(),void 0}if((a.which===k.BACKSPACE&&1==this.keydowns||a.which==k.LEFT)&&0==f.offset&&!f.length)return this.selectChoice(c.find(".select2-search-choice:not(.select2-locked)").last()),A(a),void 0;if(this.selectChoice(null),this.opened())switch(a.which){case k.UP:case k.DOWN:return this.moveHighlight(a.which===k.UP?-1:1),A(a),void 0;case k.ENTER:return this.selectHighlighted(),A(a),void 0;case k.TAB:return this.selectHighlighted({noFocus:!0}),this.close(),void 0;case k.ESC:return this.cancel(a),A(a),void 0}if(a.which!==k.TAB&&!k.isControl(a)&&!k.isFunctionKey(a)&&a.which!==k.BACKSPACE&&a.which!==k.ESC){if(a.which===k.ENTER){if(this.opts.openOnEnter===!1)return;if(a.altKey||a.ctrlKey||a.shiftKey||a.metaKey)return}this.open(),(a.which===k.PAGE_UP||a.which===k.PAGE_DOWN)&&A(a),a.which===k.ENTER&&A(a)}}})),this.search.on("keyup",this.bind(function(){this.keydowns=0,this.resizeSearch()})),this.search.on("blur",this.bind(function(b){this.container.removeClass("select2-container-active"),this.search.removeClass("select2-focused"),this.selectChoice(null),this.opened()||this.clearSearch(),b.stopImmediatePropagation(),this.opts.element.trigger(a.Event("select2-blur"))})),this.container.on("click",b,this.bind(function(b){this.isInterfaceEnabled()&&(a(b.target).closest(".select2-search-choice").length>0||(this.selectChoice(null),this.clearPlaceholder(),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.open(),this.focusSearch(),b.preventDefault()))})),this.container.on("focus",b,this.bind(function(){this.isInterfaceEnabled()&&(this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"),this.clearPlaceholder())})),this.initContainerWidth(),this.opts.element.hide(),this.clearSearch()},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.search.prop("disabled",!this.isInterfaceEnabled())},initSelection:function(){if(""===this.opts.element.val()&&""===this.opts.element.text()&&(this.updateSelection([]),this.close(),this.clearSearch()),this.select||""!==this.opts.element.val()){var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.clearSearch())})}},clearSearch:function(){var a=this.getPlaceholder(),c=this.getMaxSearchWidth();a!==b&&0===this.getVal().length&&this.search.hasClass("select2-focused")===!1?(this.search.val(a).addClass("select2-default"),this.search.width(c>0?c:this.container.css("width"))):this.search.val("").width(10)},clearPlaceholder:function(){this.search.hasClass("select2-default")&&this.search.val("").removeClass("select2-default")},opening:function(){this.clearPlaceholder(),this.resizeSearch(),this.parent.opening.apply(this,arguments),this.focusSearch(),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.updateResults(!0),this.opts.shouldFocusInput(this)&&this.search.focus(),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&this.parent.close.apply(this,arguments)},focus:function(){this.close(),this.search.focus()},isFocused:function(){return this.search.hasClass("select2-focused")},updateSelection:function(b){var c=[],d=[],e=this;a(b).each(function(){p(e.id(this),c)<0&&(c.push(e.id(this)),d.push(this))}),b=d,this.selection.find(".select2-search-choice").remove(),a(b).each(function(){e.addSelectedChoice(this)}),e.postprocessResults()},tokenize:function(){var a=this.search.val();a=this.opts.tokenizer.call(this,a,this.data(),this.bind(this.onSelect),this.opts),null!=a&&a!=b&&(this.search.val(a),a.length>0&&this.open())},onSelect:function(a,c){this.triggerSelect(a)&&""!==a.text&&(this.addSelectedChoice(a),this.opts.element.trigger({type:"selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.clearSearch(),this.updateResults(),(this.select||!this.opts.closeOnSelect)&&this.postprocessResults(a,!1,this.opts.closeOnSelect===!0),this.opts.closeOnSelect?(this.close(),this.search.width(10)):this.countSelectableResults()>0?(this.search.width(10),this.resizeSearch(),this.getMaximumSelectionSize()>0&&this.val().length>=this.getMaximumSelectionSize()?this.updateResults(!0):this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.updateResults(),this.search.select()),this.positionDropdown()):(this.close(),this.search.width(10)),this.triggerChange({added:a}),c&&c.noFocus||this.focusSearch())},cancel:function(){this.close(),this.focusSearch()},addSelectedChoice:function(c){var j,k,d=!c.locked,e=a("<li class='select2-search-choice'> <div></div> <a href='#' class='select2-search-choice-close' tabindex='-1'></a></li>"),f=a("<li class='select2-search-choice select2-locked'><div></div></li>"),g=d?e:f,h=this.id(c),i=this.getVal();j=this.opts.formatSelection(c,g.find("div"),this.opts.escapeMarkup),j!=b&&g.find("div").replaceWith(a("<div></div>").html(j)),k=this.opts.formatSelectionCssClass(c,g.find("div")),k!=b&&g.addClass(k),d&&g.find(".select2-search-choice-close").on("mousedown",A).on("click dblclick",this.bind(function(b){this.isInterfaceEnabled()&&(this.unselect(a(b.target)),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"),A(b),this.close(),this.focusSearch())})).on("focus",this.bind(function(){this.isInterfaceEnabled()&&(this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"))})),g.data("select2-data",c),g.insertBefore(this.searchContainer),i.push(h),this.setVal(i)},unselect:function(b){var d,e,c=this.getVal();if(b=b.closest(".select2-search-choice"),0===b.length)throw"Invalid argument: "+b+". Must be .select2-search-choice";if(d=b.data("select2-data")){var f=a.Event("select2-removing");if(f.val=this.id(d),f.choice=d,this.opts.element.trigger(f),f.isDefaultPrevented())return!1;for(;(e=p(this.id(d),c))>=0;)c.splice(e,1),this.setVal(c),this.select&&this.postprocessResults();return b.remove(),this.opts.element.trigger({type:"select2-removed",val:this.id(d),choice:d}),this.triggerChange({removed:d}),!0}},postprocessResults:function(a,b,c){var d=this.getVal(),e=this.results.find(".select2-result"),f=this.results.find(".select2-result-with-children"),g=this;e.each2(function(a,b){var c=g.id(b.data("select2-data"));p(c,d)>=0&&(b.addClass("select2-selected"),b.find(".select2-result-selectable").addClass("select2-selected"))}),f.each2(function(a,b){b.is(".select2-result-selectable")||0!==b.find(".select2-result-selectable:not(.select2-selected)").length||b.addClass("select2-selected")}),-1==this.highlight()&&c!==!1&&this.opts.closeOnSelect===!0&&g.highlight(0),!this.opts.createSearchChoice&&!e.filter(".select2-result:not(.select2-selected)").length>0&&(!a||a&&!a.more&&0===this.results.find(".select2-no-results").length)&&J(g.opts.formatNoMatches,"formatNoMatches")&&this.results.append("<li class='select2-no-results'>"+K(g.opts.formatNoMatches,g.opts.element,g.search.val())+"</li>")},getMaxSearchWidth:function(){return this.selection.width()-t(this.search)},resizeSearch:function(){var a,b,c,d,e,f=t(this.search);a=C(this.search)+10,b=this.search.offset().left,c=this.selection.width(),d=this.selection.offset().left,e=c-(b-d)-f,a>e&&(e=c-f),40>e&&(e=c-f),0>=e&&(e=a),this.search.width(Math.floor(e))},getVal:function(){var a;return this.select?(a=this.select.val(),null===a?[]:a):(a=this.opts.element.val(),s(a,this.opts.separator,this.opts.transformVal))},setVal:function(b){var c;this.select?this.select.val(b):(c=[],a(b).each(function(){p(this,c)<0&&c.push(this)}),this.opts.element.val(0===c.length?"":c.join(this.opts.separator)))},buildChangeDetails:function(a,b){for(var b=b.slice(0),a=a.slice(0),c=0;c<b.length;c++)for(var d=0;d<a.length;d++)r(this.opts.id(b[c]),this.opts.id(a[d]))&&(b.splice(c,1),c>0&&c--,a.splice(d,1),d--);return{added:b,removed:a}},val:function(c,d){var e,f=this;if(0===arguments.length)return this.getVal();if(e=this.data(),e.length||(e=[]),!c&&0!==c)return this.opts.element.val(""),this.updateSelection([]),this.clearSearch(),d&&this.triggerChange({added:this.data(),removed:e}),void 0;if(this.setVal(c),this.select)this.opts.initSelection(this.select,this.bind(this.updateSelection)),d&&this.triggerChange(this.buildChangeDetails(e,this.data()));else{if(this.opts.initSelection===b)throw new Error("val() cannot be called if initSelection() is not defined");this.opts.initSelection(this.opts.element,function(b){var c=a.map(b,f.id);f.setVal(c),f.updateSelection(b),f.clearSearch(),d&&f.triggerChange(f.buildChangeDetails(e,f.data()))})}this.clearSearch()},onSortStart:function(){if(this.select)throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead.");this.search.width(0),this.searchContainer.hide()},onSortEnd:function(){var b=[],c=this;this.searchContainer.show(),this.searchContainer.appendTo(this.searchContainer.parent()),this.resizeSearch(),this.selection.find(".select2-search-choice").each(function(){b.push(c.opts.id(a(this).data("select2-data")))}),this.setVal(b),this.triggerChange()},data:function(b,c){var e,f,d=this;return 0===arguments.length?this.selection.children(".select2-search-choice").map(function(){return a(this).data("select2-data")}).get():(f=this.data(),b||(b=[]),e=a.map(b,function(a){return d.opts.id(a)}),this.setVal(e),this.updateSelection(b),this.clearSearch(),c&&this.triggerChange(this.buildChangeDetails(f,this.data())),void 0)}}),a.fn.select2=function(){var d,e,f,g,h,c=Array.prototype.slice.call(arguments,0),i=["val","destroy","opened","open","close","focus","isFocused","container","dropdown","onSortStart","onSortEnd","enable","disable","readonly","positionDropdown","data","search"],j=["opened","isFocused","container","dropdown"],k=["val","data"],l={search:"externalSearch"};return this.each(function(){if(0===c.length||"object"==typeof c[0])d=0===c.length?{}:a.extend({},c[0]),d.element=a(this),"select"===d.element.get(0).tagName.toLowerCase()?h=d.element.prop("multiple"):(h=d.multiple||!1,"tags"in d&&(d.multiple=h=!0)),e=h?new window.Select2["class"].multi:new window.Select2["class"].single,e.init(d);else{if("string"!=typeof c[0])throw"Invalid arguments to select2 plugin: "+c;if(p(c[0],i)<0)throw"Unknown method: "+c[0];if(g=b,e=a(this).data("select2"),e===b)return;if(f=c[0],"container"===f?g=e.container:"dropdown"===f?g=e.dropdown:(l[f]&&(f=l[f]),g=e[f].apply(e,c.slice(1))),p(c[0],j)>=0||p(c[0],k)>=0&&1==c.length)return!1}}),g===b?this:g},a.fn.select2.defaults={width:"copy",loadMorePadding:0,closeOnSelect:!0,openOnEnter:!0,containerCss:{},dropdownCss:{},containerCssClass:"",dropdownCssClass:"",formatResult:function(a,b,c,d){var e=[];return E(this.text(a),c.term,e,d),e.join("")},transformVal:function(b){return a.trim(b)},formatSelection:function(a,c,d){return a?d(this.text(a)):b},sortResults:function(a){return a},formatResultCssClass:function(a){return a.css},formatSelectionCssClass:function(){return b},minimumResultsForSearch:0,minimumInputLength:0,maximumInputLength:null,maximumSelectionSize:0,id:function(a){return a==b?null:a.id},text:function(b){return b&&this.data&&this.data.text?a.isFunction(this.data.text)?this.data.text(b):b[this.data.text]:b.text
23
  },matcher:function(a,b){return o(""+b).toUpperCase().indexOf(o(""+a).toUpperCase())>=0},separator:",",tokenSeparators:[],tokenizer:M,escapeMarkup:F,blurOnChange:!1,selectOnBlur:!1,adaptContainerCssClass:function(a){return a},adaptDropdownCssClass:function(){return null},nextSearchTerm:function(){return b},searchInputPlaceholder:"",createSearchChoicePosition:"top",shouldFocusInput:function(a){var b="ontouchstart"in window||navigator.msMaxTouchPoints>0;return b?a.opts.minimumResultsForSearch<0?!1:!0:!0}},a.fn.select2.locales=[],a.fn.select2.locales.en={formatMatches:function(a){return 1===a?"One result is available, press enter to select it.":a+" results are available, use up and down arrow keys to navigate."},formatNoMatches:function(){return"No matches found"},formatAjaxError:function(){return"Loading failed"},formatInputTooShort:function(a,b){var c=b-a.length;return"Please enter "+c+" or more character"+(1==c?"":"s")},formatInputTooLong:function(a,b){var c=a.length-b;return"Please delete "+c+" character"+(1==c?"":"s")},formatSelectionTooBig:function(a){return"You can only select "+a+" item"+(1==a?"":"s")},formatLoadMore:function(){return"Loading more results\u2026"},formatSearching:function(){return"Searching\u2026"}},a.extend(a.fn.select2.defaults,a.fn.select2.locales.en),a.fn.select2.ajaxDefaults={transport:a.ajax,params:{type:"GET",cache:!1,dataType:"json"}},window.Select2={query:{ajax:G,local:H,tags:I},util:{debounce:w,markMatch:E,escapeMarkup:F,stripDiacritics:o},"class":{"abstract":c,single:d,multi:e}}}}(jQuery);
assets/deps/select2-3.5.2/select2_locale_ar.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Arabic translation.
3
- *
4
- * Author: Adel KEDJOUR <adel@kedjour.com>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['ar'] = {
10
- formatNoMatches: function () { return "لم يتم العثور على مطابقات"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; if (n == 1){ return "الرجاء إدخال حرف واحد على الأكثر"; } return n == 2 ? "الرجاء إدخال حرفين على الأكثر" : "الرجاء إدخال " + n + " على الأكثر"; },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; if (n == 1){ return "الرجاء إدخال حرف واحد على الأقل"; } return n == 2 ? "الرجاء إدخال حرفين على الأقل" : "الرجاء إدخال " + n + " على الأقل "; },
13
- formatSelectionTooBig: function (limit) { if (limit == 1){ return "يمكنك أن تختار إختيار واحد فقط"; } return limit == 2 ? "يمكنك أن تختار إختيارين فقط" : "يمكنك أن تختار " + limit + " إختيارات فقط"; },
14
- formatLoadMore: function (pageNumber) { return "تحميل المزيد من النتائج…"; },
15
- formatSearching: function () { return "البحث…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['ar']);
19
- })(jQuery);
1
+ /**
2
+ * Select2 Arabic translation.
3
+ *
4
+ * Author: Adel KEDJOUR <adel@kedjour.com>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['ar'] = {
10
+ formatNoMatches: function () { return "لم يتم العثور على مطابقات"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; if (n == 1){ return "الرجاء إدخال حرف واحد على الأكثر"; } return n == 2 ? "الرجاء إدخال حرفين على الأكثر" : "الرجاء إدخال " + n + " على الأكثر"; },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; if (n == 1){ return "الرجاء إدخال حرف واحد على الأقل"; } return n == 2 ? "الرجاء إدخال حرفين على الأقل" : "الرجاء إدخال " + n + " على الأقل "; },
13
+ formatSelectionTooBig: function (limit) { if (limit == 1){ return "يمكنك أن تختار إختيار واحد فقط"; } return limit == 2 ? "يمكنك أن تختار إختيارين فقط" : "يمكنك أن تختار " + limit + " إختيارات فقط"; },
14
+ formatLoadMore: function (pageNumber) { return "تحميل المزيد من النتائج…"; },
15
+ formatSearching: function () { return "البحث…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['ar']);
19
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_az.js CHANGED
@@ -1,20 +1,20 @@
1
- /**
2
- * Select2 Azerbaijani translation.
3
- *
4
- * Author: Farhad Safarov <farhad.safarov@gmail.com>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['az'] = {
10
- formatMatches: function (matches) { return matches + " nəticə mövcuddur, hərəkət etdirmək üçün yuxarı və aşağı düymələrindən istifadə edin."; },
11
- formatNoMatches: function () { return "Nəticə tapılmadı"; },
12
- formatInputTooShort: function (input, min) { var n = min - input.length; return n + " simvol daxil edin"; },
13
- formatInputTooLong: function (input, max) { var n = input.length - max; return n + " simvol silin"; },
14
- formatSelectionTooBig: function (limit) { return "Sadəcə " + limit + " element seçə bilərsiniz"; },
15
- formatLoadMore: function (pageNumber) { return "Daha çox nəticə yüklənir…"; },
16
- formatSearching: function () { return "Axtarılır…"; }
17
- };
18
-
19
- $.extend($.fn.select2.defaults, $.fn.select2.locales['az']);
20
- })(jQuery);
1
+ /**
2
+ * Select2 Azerbaijani translation.
3
+ *
4
+ * Author: Farhad Safarov <farhad.safarov@gmail.com>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['az'] = {
10
+ formatMatches: function (matches) { return matches + " nəticə mövcuddur, hərəkət etdirmək üçün yuxarı və aşağı düymələrindən istifadə edin."; },
11
+ formatNoMatches: function () { return "Nəticə tapılmadı"; },
12
+ formatInputTooShort: function (input, min) { var n = min - input.length; return n + " simvol daxil edin"; },
13
+ formatInputTooLong: function (input, max) { var n = input.length - max; return n + " simvol silin"; },
14
+ formatSelectionTooBig: function (limit) { return "Sadəcə " + limit + " element seçə bilərsiniz"; },
15
+ formatLoadMore: function (pageNumber) { return "Daha çox nəticə yüklənir…"; },
16
+ formatSearching: function () { return "Axtarılır…"; }
17
+ };
18
+
19
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['az']);
20
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_bg.js CHANGED
@@ -1,20 +1,20 @@
1
- /**
2
- * Select2 Bulgarian translation.
3
- *
4
- * @author Lubomir Vikev <lubomirvikev@gmail.com>
5
- * @author Uriy Efremochkin <efremochkin@uriy.me>
6
- */
7
- (function ($) {
8
- "use strict";
9
-
10
- $.fn.select2.locales['bg'] = {
11
- formatNoMatches: function () { return "Няма намерени съвпадения"; },
12
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Моля въведете още " + n + " символ" + (n > 1 ? "а" : ""); },
13
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Моля въведете с " + n + " по-малко символ" + (n > 1 ? "а" : ""); },
14
- formatSelectionTooBig: function (limit) { return "Можете да направите до " + limit + (limit > 1 ? " избора" : " избор"); },
15
- formatLoadMore: function (pageNumber) { return "Зареждат се още…"; },
16
- formatSearching: function () { return "Търсене…"; }
17
- };
18
-
19
- $.extend($.fn.select2.defaults, $.fn.select2.locales['bg']);
20
- })(jQuery);
1
+ /**
2
+ * Select2 Bulgarian translation.
3
+ *
4
+ * @author Lubomir Vikev <lubomirvikev@gmail.com>
5
+ * @author Uriy Efremochkin <efremochkin@uriy.me>
6
+ */
7
+ (function ($) {
8
+ "use strict";
9
+
10
+ $.fn.select2.locales['bg'] = {
11
+ formatNoMatches: function () { return "Няма намерени съвпадения"; },
12
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Моля въведете още " + n + " символ" + (n > 1 ? "а" : ""); },
13
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Моля въведете с " + n + " по-малко символ" + (n > 1 ? "а" : ""); },
14
+ formatSelectionTooBig: function (limit) { return "Можете да направите до " + limit + (limit > 1 ? " избора" : " избор"); },
15
+ formatLoadMore: function (pageNumber) { return "Зареждат се още…"; },
16
+ formatSearching: function () { return "Търсене…"; }
17
+ };
18
+
19
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['bg']);
20
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_ca.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Catalan translation.
3
- *
4
- * Author: David Planella <david.planella@gmail.com>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['ca'] = {
10
- formatNoMatches: function () { return "No s'ha trobat cap coincidència"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Introduïu " + n + " caràcter" + (n == 1 ? "" : "s") + " més"; },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Introduïu " + n + " caràcter" + (n == 1? "" : "s") + "menys"; },
13
- formatSelectionTooBig: function (limit) { return "Només podeu seleccionar " + limit + " element" + (limit == 1 ? "" : "s"); },
14
- formatLoadMore: function (pageNumber) { return "S'estan carregant més resultats…"; },
15
- formatSearching: function () { return "S'està cercant…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['ca']);
19
- })(jQuery);
1
+ /**
2
+ * Select2 Catalan translation.
3
+ *
4
+ * Author: David Planella <david.planella@gmail.com>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['ca'] = {
10
+ formatNoMatches: function () { return "No s'ha trobat cap coincidència"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Introduïu " + n + " caràcter" + (n == 1 ? "" : "s") + " més"; },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Introduïu " + n + " caràcter" + (n == 1? "" : "s") + "menys"; },
13
+ formatSelectionTooBig: function (limit) { return "Només podeu seleccionar " + limit + " element" + (limit == 1 ? "" : "s"); },
14
+ formatLoadMore: function (pageNumber) { return "S'estan carregant més resultats…"; },
15
+ formatSearching: function () { return "S'està cercant…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['ca']);
19
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_cs.js CHANGED
@@ -1,51 +1,51 @@
1
- /**
2
- * Select2 Czech translation.
3
- *
4
- * Author: Michal Marek <ahoj@michal-marek.cz>
5
- * Author - sklonovani: David Vallner <david@vallner.net>
6
- */
7
- (function ($) {
8
- "use strict";
9
- // use text for the numbers 2 through 4
10
- var smallNumbers = {
11
- 2: function(masc) { return (masc ? "dva" : "dvě"); },
12
- 3: function() { return "tři"; },
13
- 4: function() { return "čtyři"; }
14
- }
15
- $.fn.select2.locales['cs'] = {
16
- formatNoMatches: function () { return "Nenalezeny žádné položky"; },
17
- formatInputTooShort: function (input, min) {
18
- var n = min - input.length;
19
- if (n == 1) {
20
- return "Prosím zadejte ještě jeden znak";
21
- } else if (n <= 4) {
22
- return "Prosím zadejte ještě další "+smallNumbers[n](true)+" znaky";
23
- } else {
24
- return "Prosím zadejte ještě dalších "+n+" znaků";
25
- }
26
- },
27
- formatInputTooLong: function (input, max) {
28
- var n = input.length - max;
29
- if (n == 1) {
30
- return "Prosím zadejte o jeden znak méně";
31
- } else if (n <= 4) {
32
- return "Prosím zadejte o "+smallNumbers[n](true)+" znaky méně";
33
- } else {
34
- return "Prosím zadejte o "+n+" znaků méně";
35
- }
36
- },
37
- formatSelectionTooBig: function (limit) {
38
- if (limit == 1) {
39
- return "Můžete zvolit jen jednu položku";
40
- } else if (limit <= 4) {
41
- return "Můžete zvolit maximálně "+smallNumbers[limit](false)+" položky";
42
- } else {
43
- return "Můžete zvolit maximálně "+limit+" položek";
44
- }
45
- },
46
- formatLoadMore: function (pageNumber) { return "Načítají se další výsledky…"; },
47
- formatSearching: function () { return "Vyhledávání…"; }
48
- };
49
-
50
- $.extend($.fn.select2.defaults, $.fn.select2.locales['cs']);
51
- })(jQuery);
1
+ /**
2
+ * Select2 Czech translation.
3
+ *
4
+ * Author: Michal Marek <ahoj@michal-marek.cz>
5
+ * Author - sklonovani: David Vallner <david@vallner.net>
6
+ */
7
+ (function ($) {
8
+ "use strict";
9
+ // use text for the numbers 2 through 4
10
+ var smallNumbers = {
11
+ 2: function(masc) { return (masc ? "dva" : "dvě"); },
12
+ 3: function() { return "tři"; },
13
+ 4: function() { return "čtyři"; }
14
+ }
15
+ $.fn.select2.locales['cs'] = {
16
+ formatNoMatches: function () { return "Nenalezeny žádné položky"; },
17
+ formatInputTooShort: function (input, min) {
18
+ var n = min - input.length;
19
+ if (n == 1) {
20
+ return "Prosím zadejte ještě jeden znak";
21
+ } else if (n <= 4) {
22
+ return "Prosím zadejte ještě další "+smallNumbers[n](true)+" znaky";
23
+ } else {
24
+ return "Prosím zadejte ještě dalších "+n+" znaků";
25
+ }
26
+ },
27
+ formatInputTooLong: function (input, max) {
28
+ var n = input.length - max;
29
+ if (n == 1) {
30
+ return "Prosím zadejte o jeden znak méně";
31
+ } else if (n <= 4) {
32
+ return "Prosím zadejte o "+smallNumbers[n](true)+" znaky méně";
33
+ } else {
34
+ return "Prosím zadejte o "+n+" znaků méně";
35
+ }
36
+ },
37
+ formatSelectionTooBig: function (limit) {
38
+ if (limit == 1) {
39
+ return "Můžete zvolit jen jednu položku";
40
+ } else if (limit <= 4) {
41
+ return "Můžete zvolit maximálně "+smallNumbers[limit](false)+" položky";
42
+ } else {
43
+ return "Můžete zvolit maximálně "+limit+" položek";
44
+ }
45
+ },
46
+ formatLoadMore: function (pageNumber) { return "Načítají se další výsledky…"; },
47
+ formatSearching: function () { return "Vyhledávání…"; }
48
+ };
49
+
50
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['cs']);
51
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_da.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Danish translation.
3
- *
4
- * Author: Anders Jenbo <anders@jenbo.dk>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['da'] = {
10
- formatNoMatches: function () { return "Ingen resultater fundet"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Angiv venligst " + n + " tegn mere"; },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Angiv venligst " + n + " tegn mindre"; },
13
- formatSelectionTooBig: function (limit) { return "Du kan kun vælge " + limit + " emne" + (limit === 1 ? "" : "r"); },
14
- formatLoadMore: function (pageNumber) { return "Indlæser flere resultater…"; },
15
- formatSearching: function () { return "Søger…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['da']);
19
- })(jQuery);
1
+ /**
2
+ * Select2 Danish translation.
3
+ *
4
+ * Author: Anders Jenbo <anders@jenbo.dk>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['da'] = {
10
+ formatNoMatches: function () { return "Ingen resultater fundet"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Angiv venligst " + n + " tegn mere"; },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Angiv venligst " + n + " tegn mindre"; },
13
+ formatSelectionTooBig: function (limit) { return "Du kan kun vælge " + limit + " emne" + (limit === 1 ? "" : "r"); },
14
+ formatLoadMore: function (pageNumber) { return "Indlæser flere resultater…"; },
15
+ formatSearching: function () { return "Søger…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['da']);
19
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_de.js CHANGED
@@ -1,18 +1,18 @@
1
- /**
2
- * Select2 German translation
3
- */
4
- (function ($) {
5
- "use strict";
6
-
7
- $.fn.select2.locales['de'] = {
8
- formatNoMatches: function () { return "Keine Übereinstimmungen gefunden"; },
9
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Bitte " + n + " Zeichen mehr eingeben"; },
10
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Bitte " + n + " Zeichen weniger eingeben"; },
11
- formatSelectionTooBig: function (limit) { return "Sie können nur " + limit + " Eintr" + (limit === 1 ? "ag" : "äge") + " auswählen"; },
12
- formatLoadMore: function (pageNumber) { return "Lade mehr Ergebnisse…"; },
13
- formatSearching: function () { return "Suche…"; },
14
- formatMatches: function (matches) { return matches + " Ergebnis " + (matches > 1 ? "se" : "") + " verfügbar, zum Navigieren die Hoch-/Runter-Pfeiltasten verwenden."; }
15
- };
16
-
17
- $.extend($.fn.select2.defaults, $.fn.select2.locales['de']);
18
  })(jQuery);
1
+ /**
2
+ * Select2 German translation
3
+ */
4
+ (function ($) {
5
+ "use strict";
6
+
7
+ $.fn.select2.locales['de'] = {
8
+ formatNoMatches: function () { return "Keine Übereinstimmungen gefunden"; },
9
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Bitte " + n + " Zeichen mehr eingeben"; },
10
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Bitte " + n + " Zeichen weniger eingeben"; },
11
+ formatSelectionTooBig: function (limit) { return "Sie können nur " + limit + " Eintr" + (limit === 1 ? "ag" : "äge") + " auswählen"; },
12
+ formatLoadMore: function (pageNumber) { return "Lade mehr Ergebnisse…"; },
13
+ formatSearching: function () { return "Suche…"; },
14
+ formatMatches: function (matches) { return matches + " Ergebnis " + (matches > 1 ? "se" : "") + " verfügbar, zum Navigieren die Hoch-/Runter-Pfeiltasten verwenden."; }
15
+ };
16
+
17
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['de']);
18
  })(jQuery);
assets/deps/select2-3.5.2/select2_locale_el.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Greek translation.
3
- *
4
- * @author Uriy Efremochkin <efremochkin@uriy.me>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['el'] = {
10
- formatNoMatches: function () { return "Δεν βρέθηκαν αποτελέσματα"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Παρακαλούμε εισάγετε " + n + " περισσότερο" + (n > 1 ? "υς" : "") + " χαρακτήρ" + (n > 1 ? "ες" : "α"); },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Παρακαλούμε διαγράψτε " + n + " χαρακτήρ" + (n > 1 ? "ες" : "α"); },
13
- formatSelectionTooBig: function (limit) { return "Μπορείτε να επιλέξετε μόνο " + limit + " αντικείμεν" + (limit > 1 ? "α" : "ο"); },
14
- formatLoadMore: function (pageNumber) { return "Φόρτωση περισσότερων…"; },
15
- formatSearching: function () { return "Αναζήτηση…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['el']);
19
  })(jQuery);
1
+ /**
2
+ * Select2 Greek translation.
3
+ *
4
+ * @author Uriy Efremochkin <efremochkin@uriy.me>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['el'] = {
10
+ formatNoMatches: function () { return "Δεν βρέθηκαν αποτελέσματα"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Παρακαλούμε εισάγετε " + n + " περισσότερο" + (n > 1 ? "υς" : "") + " χαρακτήρ" + (n > 1 ? "ες" : "α"); },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Παρακαλούμε διαγράψτε " + n + " χαρακτήρ" + (n > 1 ? "ες" : "α"); },
13
+ formatSelectionTooBig: function (limit) { return "Μπορείτε να επιλέξετε μόνο " + limit + " αντικείμεν" + (limit > 1 ? "α" : "ο"); },
14
+ formatLoadMore: function (pageNumber) { return "Φόρτωση περισσότερων…"; },
15
+ formatSearching: function () { return "Αναζήτηση…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['el']);
19
  })(jQuery);
assets/deps/select2-3.5.2/select2_locale_en.js.template CHANGED
@@ -1,20 +1,20 @@
1
- /**
2
- * Select2 <Language> translation.
3
- *
4
- * Author: Your Name <your@email>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['en'] = {
10
- formatMatches: function (matches) { if (matches === 1) { return "One result is available, press enter to select it."; } return matches + " results are available, use up and down arrow keys to navigate."; },
11
- formatNoMatches: function () { return "No matches found"; },
12
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " or more character" + (n == 1 ? "" : "s"); },
13
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Please delete " + n + " character" + (n == 1 ? "" : "s"); },
14
- formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); },
15
- formatLoadMore: function (pageNumber) { return "Loading more results…"; },
16
- formatSearching: function () { return "Searching…"; }
17
- };
18
-
19
- $.extend($.fn.select2.defaults, $.fn.select2.locales['en']);
20
- })(jQuery);
1
+ /**
2
+ * Select2 <Language> translation.
3
+ *
4
+ * Author: Your Name <your@email>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['en'] = {
10
+ formatMatches: function (matches) { if (matches === 1) { return "One result is available, press enter to select it."; } return matches + " results are available, use up and down arrow keys to navigate."; },
11
+ formatNoMatches: function () { return "No matches found"; },
12
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " or more character" + (n == 1 ? "" : "s"); },
13
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Please delete " + n + " character" + (n == 1 ? "" : "s"); },
14
+ formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); },
15
+ formatLoadMore: function (pageNumber) { return "Loading more results…"; },
16
+ formatSearching: function () { return "Searching…"; }
17
+ };
18
+
19
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['en']);
20
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_es.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Spanish translation
3
- */
4
- (function ($) {
5
- "use strict";
6
-
7
- $.fn.select2.locales['es'] = {
8
- formatMatches: function (matches) { if (matches === 1) { return "Un resultado disponible, presione enter para seleccionarlo."; } return matches + " resultados disponibles, use las teclas de dirección para navegar."; },
9
- formatNoMatches: function () { return "No se encontraron resultados"; },
10
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Por favor, introduzca " + n + " car" + (n == 1? "ácter" : "acteres"); },
11
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Por favor, elimine " + n + " car" + (n == 1? "ácter" : "acteres"); },
12
- formatSelectionTooBig: function (limit) { return "Sólo puede seleccionar " + limit + " elemento" + (limit == 1 ? "" : "s"); },
13
- formatLoadMore: function (pageNumber) { return "Cargando más resultados…"; },
14
- formatSearching: function () { return "Buscando…"; },
15
- formatAjaxError: function() { return "La carga falló"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['es']);
19
- })(jQuery);
1
+ /**
2
+ * Select2 Spanish translation
3
+ */
4
+ (function ($) {
5
+ "use strict";
6
+
7
+ $.fn.select2.locales['es'] = {
8
+ formatMatches: function (matches) { if (matches === 1) { return "Un resultado disponible, presione enter para seleccionarlo."; } return matches + " resultados disponibles, use las teclas de dirección para navegar."; },
9
+ formatNoMatches: function () { return "No se encontraron resultados"; },
10
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Por favor, introduzca " + n + " car" + (n == 1? "ácter" : "acteres"); },
11
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Por favor, elimine " + n + " car" + (n == 1? "ácter" : "acteres"); },
12
+ formatSelectionTooBig: function (limit) { return "Sólo puede seleccionar " + limit + " elemento" + (limit == 1 ? "" : "s"); },
13
+ formatLoadMore: function (pageNumber) { return "Cargando más resultados…"; },
14
+ formatSearching: function () { return "Buscando…"; },
15
+ formatAjaxError: function() { return "La carga falló"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['es']);
19
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_et.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Estonian translation.
3
- *
4
- * Author: Kuldar Kalvik <kuldar@kalvik.ee>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['et'] = {
10
- formatNoMatches: function () { return "Tulemused puuduvad"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Sisesta " + n + " täht" + (n == 1 ? "" : "e") + " rohkem"; },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Sisesta " + n + " täht" + (n == 1? "" : "e") + " vähem"; },
13
- formatSelectionTooBig: function (limit) { return "Saad vaid " + limit + " tulemus" + (limit == 1 ? "e" : "t") + " valida"; },
14
- formatLoadMore: function (pageNumber) { return "Laen tulemusi.."; },
15
- formatSearching: function () { return "Otsin.."; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['et']);
19
- })(jQuery);
1
+ /**
2
+ * Select2 Estonian translation.
3
+ *
4
+ * Author: Kuldar Kalvik <kuldar@kalvik.ee>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['et'] = {
10
+ formatNoMatches: function () { return "Tulemused puuduvad"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Sisesta " + n + " täht" + (n == 1 ? "" : "e") + " rohkem"; },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Sisesta " + n + " täht" + (n == 1? "" : "e") + " vähem"; },
13
+ formatSelectionTooBig: function (limit) { return "Saad vaid " + limit + " tulemus" + (limit == 1 ? "e" : "t") + " valida"; },
14
+ formatLoadMore: function (pageNumber) { return "Laen tulemusi.."; },
15
+ formatSearching: function () { return "Otsin.."; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['et']);
19
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_eu.js CHANGED
@@ -1,45 +1,45 @@
1
- /**
2
- * Select2 Basque translation.
3
- *
4
- * Author: Julen Ruiz Aizpuru <julenx at gmail dot com>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['eu'] = {
10
- formatNoMatches: function () {
11
- return "Ez da bat datorrenik aurkitu";
12
- },
13
- formatInputTooShort: function (input, min) {
14
- var n = min - input.length;
15
- if (n === 1) {
16
- return "Idatzi karaktere bat gehiago";
17
- } else {
18
- return "Idatzi " + n + " karaktere gehiago";
19
- }
20
- },
21
- formatInputTooLong: function (input, max) {
22
- var n = input.length - max;
23
- if (n === 1) {
24
- return "Idatzi karaktere bat gutxiago";
25
- } else {
26
- return "Idatzi " + n + " karaktere gutxiago";
27
- }
28
- },
29
- formatSelectionTooBig: function (limit) {
30
- if (limit === 1 ) {
31
- return "Elementu bakarra hauta dezakezu";
32
- } else {
33
- return limit + " elementu hauta ditzakezu soilik";
34
- }
35
- },
36
- formatLoadMore: function (pageNumber) {
37
- return "Emaitza gehiago kargatzen…";
38
- },
39
- formatSearching: function () {
40
- return "Bilatzen…";
41
- }
42
- };
43
-
44
- $.extend($.fn.select2.defaults, $.fn.select2.locales['eu']);
45
- })(jQuery);
1
+ /**
2
+ * Select2 Basque translation.
3
+ *
4
+ * Author: Julen Ruiz Aizpuru <julenx at gmail dot com>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['eu'] = {
10
+ formatNoMatches: function () {
11
+ return "Ez da bat datorrenik aurkitu";
12
+ },
13
+ formatInputTooShort: function (input, min) {
14
+ var n = min - input.length;
15
+ if (n === 1) {
16
+ return "Idatzi karaktere bat gehiago";
17
+ } else {
18
+ return "Idatzi " + n + " karaktere gehiago";
19
+ }
20
+ },
21
+ formatInputTooLong: function (input, max) {
22
+ var n = input.length - max;
23
+ if (n === 1) {
24
+ return "Idatzi karaktere bat gutxiago";
25
+ } else {
26
+ return "Idatzi " + n + " karaktere gutxiago";
27
+ }
28
+ },
29
+ formatSelectionTooBig: function (limit) {
30
+ if (limit === 1 ) {
31
+ return "Elementu bakarra hauta dezakezu";
32
+ } else {
33
+ return limit + " elementu hauta ditzakezu soilik";
34
+ }
35
+ },
36
+ formatLoadMore: function (pageNumber) {
37
+ return "Emaitza gehiago kargatzen…";
38
+ },
39
+ formatSearching: function () {
40
+ return "Bilatzen…";
41
+ }
42
+ };
43
+
44
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['eu']);
45
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_fa.js CHANGED
@@ -1,21 +1,21 @@
1
- /**
2
- * Select2 Persian translation.
3
- *
4
- * Author: Ali Choopan <choopan@arsh.co>
5
- * Author: Ebrahim Byagowi <ebrahim@gnu.org>
6
- */
7
- (function ($) {
8
- "use strict";
9
-
10
- $.fn.select2.locales['fa'] = {
11
- formatMatches: function (matches) { return matches + " نتیجه موجود است، کلیدهای جهت بالا و پایین را برای گشتن استفاده کنید."; },
12
- formatNoMatches: function () { return "نتیجه‌ای یافت نشد."; },
13
- formatInputTooShort: function (input, min) { var n = min - input.length; return "لطفاً " + n + " نویسه بیشتر وارد نمایید"; },
14
- formatInputTooLong: function (input, max) { var n = input.length - max; return "لطفاً " + n + " نویسه را حذف کنید."; },
15
- formatSelectionTooBig: function (limit) { return "شما فقط می‌توانید " + limit + " مورد را انتخاب کنید"; },
16
- formatLoadMore: function (pageNumber) { return "در حال بارگیری موارد بیشتر…"; },
17
- formatSearching: function () { return "در حال جستجو…"; }
18
- };
19
-
20
- $.extend($.fn.select2.defaults, $.fn.select2.locales['fa']);
21
- })(jQuery);
1
+ /**
2
+ * Select2 Persian translation.
3
+ *
4
+ * Author: Ali Choopan <choopan@arsh.co>
5
+ * Author: Ebrahim Byagowi <ebrahim@gnu.org>
6
+ */
7
+ (function ($) {
8
+ "use strict";
9
+
10
+ $.fn.select2.locales['fa'] = {
11
+ formatMatches: function (matches) { return matches + " نتیجه موجود است، کلیدهای جهت بالا و پایین را برای گشتن استفاده کنید."; },
12
+ formatNoMatches: function () { return "نتیجه‌ای یافت نشد."; },
13
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "لطفاً " + n + " نویسه بیشتر وارد نمایید"; },
14
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "لطفاً " + n + " نویسه را حذف کنید."; },
15
+ formatSelectionTooBig: function (limit) { return "شما فقط می‌توانید " + limit + " مورد را انتخاب کنید"; },
16
+ formatLoadMore: function (pageNumber) { return "در حال بارگیری موارد بیشتر…"; },
17
+ formatSearching: function () { return "در حال جستجو…"; }
18
+ };
19
+
20
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['fa']);
21
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_fi.js CHANGED
@@ -1,30 +1,30 @@
1
- /**
2
- * Select2 Finnish translation
3
- */
4
- (function ($) {
5
- "use strict";
6
- $.fn.select2.locales['fi'] = {
7
- formatNoMatches: function () {
8
- return "Ei tuloksia";
9
- },
10
- formatInputTooShort: function (input, min) {
11
- var n = min - input.length;
12
- return "Ole hyvä ja anna " + n + " merkkiä lisää";
13
- },
14
- formatInputTooLong: function (input, max) {
15
- var n = input.length - max;
16
- return "Ole hyvä ja anna " + n + " merkkiä vähemmän";
17
- },
18
- formatSelectionTooBig: function (limit) {
19
- return "Voit valita ainoastaan " + limit + " kpl";
20
- },
21
- formatLoadMore: function (pageNumber) {
22
- return "Ladataan lisää tuloksia…";
23
- },
24
- formatSearching: function () {
25
- return "Etsitään…";
26
- }
27
- };
28
-
29
- $.extend($.fn.select2.defaults, $.fn.select2.locales['fi']);
30
- })(jQuery);
1
+ /**
2
+ * Select2 Finnish translation
3
+ */
4
+ (function ($) {
5
+ "use strict";
6
+ $.fn.select2.locales['fi'] = {
7
+ formatNoMatches: function () {
8
+ return "Ei tuloksia";
9
+ },
10
+ formatInputTooShort: function (input, min) {
11
+ var n = min - input.length;
12
+ return "Ole hyvä ja anna " + n + " merkkiä lisää";
13
+ },
14
+ formatInputTooLong: function (input, max) {
15
+ var n = input.length - max;
16
+ return "Ole hyvä ja anna " + n + " merkkiä vähemmän";
17
+ },
18
+ formatSelectionTooBig: function (limit) {
19
+ return "Voit valita ainoastaan " + limit + " kpl";
20
+ },
21
+ formatLoadMore: function (pageNumber) {
22
+ return "Ladataan lisää tuloksia…";
23
+ },
24
+ formatSearching: function () {
25
+ return "Etsitään…";
26
+ }
27
+ };
28
+
29
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['fi']);
30
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_fr.js CHANGED
@@ -1,18 +1,18 @@
1
- /**
2
- * Select2 French translation
3
- */
4
- (function ($) {
5
- "use strict";
6
-
7
- $.fn.select2.locales['fr'] = {
8
- formatMatches: function (matches) { return matches + " résultats sont disponibles, utilisez les flèches haut et bas pour naviguer."; },
9
- formatNoMatches: function () { return "Aucun résultat trouvé"; },
10
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Saisissez " + n + " caractère" + (n == 1? "" : "s") + " supplémentaire" + (n == 1? "" : "s") ; },
11
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Supprimez " + n + " caractère" + (n == 1? "" : "s"); },
12
- formatSelectionTooBig: function (limit) { return "Vous pouvez seulement sélectionner " + limit + " élément" + (limit == 1 ? "" : "s"); },
13
- formatLoadMore: function (pageNumber) { return "Chargement de résultats supplémentaires…"; },
14
- formatSearching: function () { return "Recherche en cours…"; }
15
- };
16
-
17
- $.extend($.fn.select2.defaults, $.fn.select2.locales['fr']);
18
- })(jQuery);
1
+ /**
2
+ * Select2 French translation
3
+ */
4
+ (function ($) {
5
+ "use strict";
6
+
7
+ $.fn.select2.locales['fr'] = {
8
+ formatMatches: function (matches) { return matches + " résultats sont disponibles, utilisez les flèches haut et bas pour naviguer."; },
9
+ formatNoMatches: function () { return "Aucun résultat trouvé"; },
10
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Saisissez " + n + " caractère" + (n == 1? "" : "s") + " supplémentaire" + (n == 1? "" : "s") ; },
11
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Supprimez " + n + " caractère" + (n == 1? "" : "s"); },
12
+ formatSelectionTooBig: function (limit) { return "Vous pouvez seulement sélectionner " + limit + " élément" + (limit == 1 ? "" : "s"); },
13
+ formatLoadMore: function (pageNumber) { return "Chargement de résultats supplémentaires…"; },
14
+ formatSearching: function () { return "Recherche en cours…"; }
15
+ };
16
+
17
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['fr']);
18
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_gl.js CHANGED
@@ -1,45 +1,45 @@
1
- /**
2
- * Select2 Galician translation
3
- *
4
- * Author: Leandro Regueiro <leandro.regueiro@gmail.com>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['gl'] = {
10
- formatNoMatches: function () {
11
- return "Non se atoparon resultados";
12
- },
13
- formatInputTooShort: function (input, min) {
14
- var n = min - input.length;
15
- if (n === 1) {
16
- return "Engada un carácter";
17
- } else {
18
- return "Engada " + n + " caracteres";
19
- }
20
- },
21
- formatInputTooLong: function (input, max) {
22
- var n = input.length - max;
23
- if (n === 1) {
24
- return "Elimine un carácter";
25
- } else {
26
- return "Elimine " + n + " caracteres";
27
- }
28
- },
29
- formatSelectionTooBig: function (limit) {
30
- if (limit === 1 ) {
31
- return "Só pode seleccionar un elemento";
32
- } else {
33
- return "Só pode seleccionar " + limit + " elementos";
34
- }
35
- },
36
- formatLoadMore: function (pageNumber) {
37
- return "Cargando máis resultados…";
38
- },
39
- formatSearching: function () {
40
- return "Buscando…";
41
- }
42
- };
43
-
44
- $.extend($.fn.select2.defaults, $.fn.select2.locales['gl']);
45
- })(jQuery);
1
+ /**
2
+ * Select2 Galician translation
3
+ *
4
+ * Author: Leandro Regueiro <leandro.regueiro@gmail.com>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['gl'] = {
10
+ formatNoMatches: function () {
11
+ return "Non se atoparon resultados";
12
+ },
13
+ formatInputTooShort: function (input, min) {
14
+ var n = min - input.length;
15
+ if (n === 1) {
16
+ return "Engada un carácter";
17
+ } else {
18
+ return "Engada " + n + " caracteres";
19
+ }
20
+ },
21
+ formatInputTooLong: function (input, max) {
22
+ var n = input.length - max;
23
+ if (n === 1) {
24
+ return "Elimine un carácter";
25
+ } else {
26
+ return "Elimine " + n + " caracteres";
27
+ }
28
+ },
29
+ formatSelectionTooBig: function (limit) {
30
+ if (limit === 1 ) {
31
+ return "Só pode seleccionar un elemento";
32
+ } else {
33
+ return "Só pode seleccionar " + limit + " elementos";
34
+ }
35
+ },
36
+ formatLoadMore: function (pageNumber) {
37
+ return "Cargando máis resultados…";
38
+ },
39
+ formatSearching: function () {
40
+ return "Buscando…";
41
+ }
42
+ };
43
+
44
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['gl']);
45
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_he.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Hebrew translation.
3
- *
4
- * Author: Yakir Sitbon <http://www.yakirs.net/>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['he'] = {
10
- formatNoMatches: function () { return "לא נמצאו התאמות"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "נא להזין עוד " + n + " תווים נוספים"; },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return "נא להזין פחות " + n + " תווים"; },
13
- formatSelectionTooBig: function (limit) { return "ניתן לבחור " + limit + " פריטים"; },
14
- formatLoadMore: function (pageNumber) { return "טוען תוצאות נוספות…"; },
15
- formatSearching: function () { return "מחפש…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['he']);
19
- })(jQuery);
1
+ /**
2
+ * Select2 Hebrew translation.
3
+ *
4
+ * Author: Yakir Sitbon <http://www.yakirs.net/>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['he'] = {
10
+ formatNoMatches: function () { return "לא נמצאו התאמות"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "נא להזין עוד " + n + " תווים נוספים"; },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "נא להזין פחות " + n + " תווים"; },
13
+ formatSelectionTooBig: function (limit) { return "ניתן לבחור " + limit + " פריטים"; },
14
+ formatLoadMore: function (pageNumber) { return "טוען תוצאות נוספות…"; },
15
+ formatSearching: function () { return "מחפש…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['he']);
19
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_hr.js CHANGED
@@ -1,24 +1,24 @@
1
- /**
2
- * Select2 Croatian translation.
3
- *
4
- * @author Edi Modrić <edi.modric@gmail.com>
5
- * @author Uriy Efremochkin <efremochkin@uriy.me>
6
- */
7
- (function ($) {
8
- "use strict";
9
-
10
- $.fn.select2.locales['hr'] = {
11
- formatNoMatches: function () { return "Nema rezultata"; },
12
- formatInputTooShort: function (input, min) { return "Unesite još" + character(min - input.length); },
13
- formatInputTooLong: function (input, max) { return "Unesite" + character(input.length - max) + " manje"; },
14
- formatSelectionTooBig: function (limit) { return "Maksimalan broj odabranih stavki je " + limit; },
15
- formatLoadMore: function (pageNumber) { return "Učitavanje rezultata…"; },
16
- formatSearching: function () { return "Pretraga…"; }
17
- };
18
-
19
- $.extend($.fn.select2.defaults, $.fn.select2.locales['hr']);
20
-
21
- function character (n) {
22
- return " " + n + " znak" + (n%10 < 5 && n%10 > 0 && (n%100 < 5 || n%100 > 19) ? n%10 > 1 ? "a" : "" : "ova");
23
- }
24
- })(jQuery);
1
+ /**
2
+ * Select2 Croatian translation.
3
+ *
4
+ * @author Edi Modrić <edi.modric@gmail.com>
5
+ * @author Uriy Efremochkin <efremochkin@uriy.me>
6
+ */
7
+ (function ($) {
8
+ "use strict";
9
+
10
+ $.fn.select2.locales['hr'] = {
11
+ formatNoMatches: function () { return "Nema rezultata"; },
12
+ formatInputTooShort: function (input, min) { return "Unesite još" + character(min - input.length); },
13
+ formatInputTooLong: function (input, max) { return "Unesite" + character(input.length - max) + " manje"; },
14
+ formatSelectionTooBig: function (limit) { return "Maksimalan broj odabranih stavki je " + limit; },
15
+ formatLoadMore: function (pageNumber) { return "Učitavanje rezultata…"; },
16
+ formatSearching: function () { return "Pretraga…"; }
17
+ };
18
+
19
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['hr']);
20
+
21
+ function character (n) {
22
+ return " " + n + " znak" + (n%10 < 5 && n%10 > 0 && (n%100 < 5 || n%100 > 19) ? n%10 > 1 ? "a" : "" : "ova");
23
+ }
24
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_hu.js CHANGED
@@ -1,17 +1,17 @@
1
- /**
2
- * Select2 Hungarian translation
3
- */
4
- (function ($) {
5
- "use strict";
6
-
7
- $.fn.select2.locales['hu'] = {
8
- formatNoMatches: function () { return "Nincs találat."; },
9
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Túl rövid. Még " + n + " karakter hiányzik."; },
10
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Túl hosszú. " + n + " karakterrel több, mint kellene."; },
11
- formatSelectionTooBig: function (limit) { return "Csak " + limit + " elemet lehet kiválasztani."; },
12
- formatLoadMore: function (pageNumber) { return "Töltés…"; },
13
- formatSearching: function () { return "Keresés…"; }
14
- };
15
-
16
- $.extend($.fn.select2.defaults, $.fn.select2.locales['hu']);
17
- })(jQuery);
1
+ /**
2
+ * Select2 Hungarian translation
3
+ */
4
+ (function ($) {
5
+ "use strict";
6
+
7
+ $.fn.select2.locales['hu'] = {
8
+ formatNoMatches: function () { return "Nincs találat."; },
9
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Túl rövid. Még " + n + " karakter hiányzik."; },
10
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Túl hosszú. " + n + " karakterrel több, mint kellene."; },
11
+ formatSelectionTooBig: function (limit) { return "Csak " + limit + " elemet lehet kiválasztani."; },
12
+ formatLoadMore: function (pageNumber) { return "Töltés…"; },
13
+ formatSearching: function () { return "Keresés…"; }
14
+ };
15
+
16
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['hu']);
17
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_id.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Indonesian translation.
3
- *
4
- * Author: Ibrahim Yusuf <ibrahim7usuf@gmail.com>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['id'] = {
10
- formatNoMatches: function () { return "Tidak ada data yang sesuai"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Masukkan " + n + " huruf lagi" + (n == 1 ? "" : "s"); },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Hapus " + n + " huruf" + (n == 1 ? "" : "s"); },
13
- formatSelectionTooBig: function (limit) { return "Anda hanya dapat memilih " + limit + " pilihan" + (limit == 1 ? "" : "s"); },
14
- formatLoadMore: function (pageNumber) { return "Mengambil data…"; },
15
- formatSearching: function () { return "Mencari…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['id']);
19
- })(jQuery);
1
+ /**
2
+ * Select2 Indonesian translation.
3
+ *
4
+ * Author: Ibrahim Yusuf <ibrahim7usuf@gmail.com>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['id'] = {
10
+ formatNoMatches: function () { return "Tidak ada data yang sesuai"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Masukkan " + n + " huruf lagi" + (n == 1 ? "" : "s"); },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Hapus " + n + " huruf" + (n == 1 ? "" : "s"); },
13
+ formatSelectionTooBig: function (limit) { return "Anda hanya dapat memilih " + limit + " pilihan" + (limit == 1 ? "" : "s"); },
14
+ formatLoadMore: function (pageNumber) { return "Mengambil data…"; },
15
+ formatSearching: function () { return "Mencari…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['id']);
19
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_is.js CHANGED
@@ -1,17 +1,17 @@
1
- /**
2
- * Select2 Icelandic translation.
3
- */
4
- (function ($) {
5
- "use strict";
6
-
7
- $.fn.select2.locales['is'] = {
8
- formatNoMatches: function () { return "Ekkert fannst"; },
9
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Vinsamlegast skrifið " + n + " staf" + (n > 1 ? "i" : "") + " í viðbót"; },
10
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Vinsamlegast styttið texta um " + n + " staf" + (n > 1 ? "i" : ""); },
11
- formatSelectionTooBig: function (limit) { return "Þú getur aðeins valið " + limit + " atriði"; },
12
- formatLoadMore: function (pageNumber) { return "Sæki fleiri niðurstöður…"; },
13
- formatSearching: function () { return "Leita…"; }
14
- };
15
-
16
- $.extend($.fn.select2.defaults, $.fn.select2.locales['is']);
17
- })(jQuery);
1
+ /**
2
+ * Select2 Icelandic translation.
3
+ */
4
+ (function ($) {
5
+ "use strict";
6
+
7
+ $.fn.select2.locales['is'] = {
8
+ formatNoMatches: function () { return "Ekkert fannst"; },
9
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Vinsamlegast skrifið " + n + " staf" + (n > 1 ? "i" : "") + " í viðbót"; },
10
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Vinsamlegast styttið texta um " + n + " staf" + (n > 1 ? "i" : ""); },
11
+ formatSelectionTooBig: function (limit) { return "Þú getur aðeins valið " + limit + " atriði"; },
12
+ formatLoadMore: function (pageNumber) { return "Sæki fleiri niðurstöður…"; },
13
+ formatSearching: function () { return "Leita…"; }
14
+ };
15
+
16
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['is']);
17
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_it.js CHANGED
@@ -1,17 +1,17 @@
1
- /**
2
- * Select2 Italian translation
3
- */
4
- (function ($) {
5
- "use strict";
6
-
7
- $.fn.select2.locales['it'] = {
8
- formatNoMatches: function () { return "Nessuna corrispondenza trovata"; },
9
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Inserisci ancora " + n + " caratter" + (n == 1? "e" : "i"); },
10
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Inserisci " + n + " caratter" + (n == 1? "e" : "i") + " in meno"; },
11
- formatSelectionTooBig: function (limit) { return "Puoi selezionare solo " + limit + " element" + (limit == 1 ? "o" : "i"); },
12
- formatLoadMore: function (pageNumber) { return "Caricamento in corso…"; },
13
- formatSearching: function () { return "Ricerca…"; }
14
- };
15
-
16
- $.extend($.fn.select2.defaults, $.fn.select2.locales['it']);
17
  })(jQuery);
1
+ /**
2
+ * Select2 Italian translation
3
+ */
4
+ (function ($) {
5
+ "use strict";
6
+
7
+ $.fn.select2.locales['it'] = {
8
+ formatNoMatches: function () { return "Nessuna corrispondenza trovata"; },
9
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Inserisci ancora " + n + " caratter" + (n == 1? "e" : "i"); },
10
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Inserisci " + n + " caratter" + (n == 1? "e" : "i") + " in meno"; },
11
+ formatSelectionTooBig: function (limit) { return "Puoi selezionare solo " + limit + " element" + (limit == 1 ? "o" : "i"); },
12
+ formatLoadMore: function (pageNumber) { return "Caricamento in corso…"; },
13
+ formatSearching: function () { return "Ricerca…"; }
14
+ };
15
+
16
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['it']);
17
  })(jQuery);
assets/deps/select2-3.5.2/select2_locale_ja.js CHANGED
@@ -1,17 +1,17 @@
1
- /**
2
- * Select2 Japanese translation.
3
- */
4
- (function ($) {
5
- "use strict";
6
-
7
- $.fn.select2.locales['ja'] = {
8
- formatNoMatches: function () { return "該当なし"; },
9
- formatInputTooShort: function (input, min) { var n = min - input.length; return "後" + n + "文字入れてください"; },
10
- formatInputTooLong: function (input, max) { var n = input.length - max; return "検索文字列が" + n + "文字長すぎます"; },
11
- formatSelectionTooBig: function (limit) { return "最多で" + limit + "項目までしか選択できません"; },
12
- formatLoadMore: function (pageNumber) { return "読込中・・・"; },
13
- formatSearching: function () { return "検索中・・・"; }
14
- };
15
-
16
- $.extend($.fn.select2.defaults, $.fn.select2.locales['ja']);
17
- })(jQuery);
1
+ /**
2
+ * Select2 Japanese translation.
3
+ */
4
+ (function ($) {
5
+ "use strict";
6
+
7
+ $.fn.select2.locales['ja'] = {
8
+ formatNoMatches: function () { return "該当なし"; },
9
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "後" + n + "文字入れてください"; },
10
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "検索文字列が" + n + "文字長すぎます"; },
11
+ formatSelectionTooBig: function (limit) { return "最多で" + limit + "項目までしか選択できません"; },
12
+ formatLoadMore: function (pageNumber) { return "読込中・・・"; },
13
+ formatSearching: function () { return "検索中・・・"; }
14
+ };
15
+
16
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['ja']);
17
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_ka.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Georgian (Kartuli) translation.
3
- *
4
- * Author: Dimitri Kurashvili dimakura@gmail.com
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['ka'] = {
10
- formatNoMatches: function () { return "ვერ მოიძებნა"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "გთხოვთ შეიყვანოთ კიდევ " + n + " სიმბოლო"; },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return "გთხოვთ წაშალოთ " + n + " სიმბოლო"; },
13
- formatSelectionTooBig: function (limit) { return "თქვენ შეგიძლიათ მხოლოდ " + limit + " ჩანაწერის მონიშვნა"; },
14
- formatLoadMore: function (pageNumber) { return "შედეგის ჩატვირთვა…"; },
15
- formatSearching: function () { return "ძებნა…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['ka']);
19
- })(jQuery);
1
+ /**
2
+ * Select2 Georgian (Kartuli) translation.
3
+ *
4
+ * Author: Dimitri Kurashvili dimakura@gmail.com
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['ka'] = {
10
+ formatNoMatches: function () { return "ვერ მოიძებნა"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "გთხოვთ შეიყვანოთ კიდევ " + n + " სიმბოლო"; },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "გთხოვთ წაშალოთ " + n + " სიმბოლო"; },
13
+ formatSelectionTooBig: function (limit) { return "თქვენ შეგიძლიათ მხოლოდ " + limit + " ჩანაწერის მონიშვნა"; },
14
+ formatLoadMore: function (pageNumber) { return "შედეგის ჩატვირთვა…"; },
15
+ formatSearching: function () { return "ძებნა…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['ka']);
19
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_ko.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Korean translation.
3
- *
4
- * @author Swen Mun <longfinfunnel@gmail.com>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['ko'] = {
10
- formatNoMatches: function () { return "결과 없음"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "너무 짧습니다. "+n+"글자 더 입력해주세요."; },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return "너무 깁니다. "+n+"글자 지워주세요."; },
13
- formatSelectionTooBig: function (limit) { return "최대 "+limit+"개까지만 선택하실 수 있습니다."; },
14
- formatLoadMore: function (pageNumber) { return "불러오는 중…"; },
15
- formatSearching: function () { return "검색 중…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['ko']);
19
- })(jQuery);
1
+ /**
2
+ * Select2 Korean translation.
3
+ *
4
+ * @author Swen Mun <longfinfunnel@gmail.com>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['ko'] = {
10
+ formatNoMatches: function () { return "결과 없음"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "너무 짧습니다. "+n+"글자 더 입력해주세요."; },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "너무 깁니다. "+n+"글자 지워주세요."; },
13
+ formatSelectionTooBig: function (limit) { return "최대 "+limit+"개까지만 선택하실 수 있습니다."; },
14
+ formatLoadMore: function (pageNumber) { return "불러오는 중…"; },
15
+ formatSearching: function () { return "검색 중…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['ko']);
19
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_lt.js CHANGED
@@ -1,26 +1,26 @@
1
- /**
2
- * Select2 Lithuanian translation.
3
- *
4
- * @author CRONUS Karmalakas <cronus dot karmalakas at gmail dot com>
5
- * @author Uriy Efremochkin <efremochkin@uriy.me>
6
- */
7
- (function ($) {
8
- "use strict";
9
-
10
- $.fn.select2.locales['lt'] = {
11
- formatNoMatches: function () { return "Atitikmenų nerasta"; },
12
- formatInputTooShort: function (input, min) { return "Įrašykite dar" + character(min - input.length); },
13
- formatInputTooLong: function (input, max) { return "Pašalinkite" + character(input.length - max); },
14
- formatSelectionTooBig: function (limit) {
15
- return "Jūs galite pasirinkti tik " + limit + " element" + ((limit%100 > 9 && limit%100 < 21) || limit%10 == 0 ? "ų" : limit%10 > 1 ? "us" : "ą");
16
- },
17
- formatLoadMore: function (pageNumber) { return "Kraunama daugiau rezultatų…"; },
18
- formatSearching: function () { return "Ieškoma…"; }
19
- };
20
-
21
- $.extend($.fn.select2.defaults, $.fn.select2.locales['lt']);
22
-
23
- function character (n) {
24
- return " " + n + " simbol" + ((n%100 > 9 && n%100 < 21) || n%10 == 0 ? "ių" : n%10 > 1 ? "ius" : "į");
25
- }
26
- })(jQuery);
1
+ /**
2
+ * Select2 Lithuanian translation.
3
+ *
4
+ * @author CRONUS Karmalakas <cronus dot karmalakas at gmail dot com>
5
+ * @author Uriy Efremochkin <efremochkin@uriy.me>
6
+ */
7
+ (function ($) {
8
+ "use strict";
9
+
10
+ $.fn.select2.locales['lt'] = {
11
+ formatNoMatches: function () { return "Atitikmenų nerasta"; },
12
+ formatInputTooShort: function (input, min) { return "Įrašykite dar" + character(min - input.length); },
13
+ formatInputTooLong: function (input, max) { return "Pašalinkite" + character(input.length - max); },
14
+ formatSelectionTooBig: function (limit) {
15
+ return "Jūs galite pasirinkti tik " + limit + " element" + ((limit%100 > 9 && limit%100 < 21) || limit%10 == 0 ? "ų" : limit%10 > 1 ? "us" : "ą");
16
+ },
17
+ formatLoadMore: function (pageNumber) { return "Kraunama daugiau rezultatų…"; },
18
+ formatSearching: function () { return "Ieškoma…"; }
19
+ };
20
+
21
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['lt']);
22
+
23
+ function character (n) {
24
+ return " " + n + " simbol" + ((n%100 > 9 && n%100 < 21) || n%10 == 0 ? "ių" : n%10 > 1 ? "ius" : "į");
25
+ }
26
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_lv.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Latvian translation.
3
- *
4
- * @author Uriy Efremochkin <efremochkin@uriy.me>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['lv'] = {
10
- formatNoMatches: function () { return "Sakritību nav"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Lūdzu ievadiet vēl " + n + " simbol" + (n == 11 ? "us" : n%10 == 1 ? "u" : "us"); },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Lūdzu ievadiet par " + n + " simbol" + (n == 11 ? "iem" : n%10 == 1 ? "u" : "iem") + " mazāk"; },
13
- formatSelectionTooBig: function (limit) { return "Jūs varat izvēlēties ne vairāk kā " + limit + " element" + (limit == 11 ? "us" : limit%10 == 1 ? "u" : "us"); },
14
- formatLoadMore: function (pageNumber) { return "Datu ielāde…"; },
15
- formatSearching: function () { return "Meklēšana…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['lv']);
19
- })(jQuery);
1
+ /**
2
+ * Select2 Latvian translation.
3
+ *
4
+ * @author Uriy Efremochkin <efremochkin@uriy.me>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['lv'] = {
10
+ formatNoMatches: function () { return "Sakritību nav"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Lūdzu ievadiet vēl " + n + " simbol" + (n == 11 ? "us" : n%10 == 1 ? "u" : "us"); },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Lūdzu ievadiet par " + n + " simbol" + (n == 11 ? "iem" : n%10 == 1 ? "u" : "iem") + " mazāk"; },
13
+ formatSelectionTooBig: function (limit) { return "Jūs varat izvēlēties ne vairāk kā " + limit + " element" + (limit == 11 ? "us" : limit%10 == 1 ? "u" : "us"); },
14
+ formatLoadMore: function (pageNumber) { return "Datu ielāde…"; },
15
+ formatSearching: function () { return "Meklēšana…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['lv']);
19
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_mk.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Macedonian translation.
3
- *
4
- * Author: Marko Aleksic <psybaron@gmail.com>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['mk'] = {
10
- formatNoMatches: function () { return "Нема пронајдено совпаѓања"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Ве молиме внесете уште " + n + " карактер" + (n == 1 ? "" : "и"); },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Ве молиме внесете " + n + " помалку карактер" + (n == 1? "" : "и"); },
13
- formatSelectionTooBig: function (limit) { return "Можете да изберете само " + limit + " ставк" + (limit == 1 ? "а" : "и"); },
14
- formatLoadMore: function (pageNumber) { return "Вчитување резултати…"; },
15
- formatSearching: function () { return "Пребарување…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['mk']);
19
  })(jQuery);
1
+ /**
2
+ * Select2 Macedonian translation.
3
+ *
4
+ * Author: Marko Aleksic <psybaron@gmail.com>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['mk'] = {
10
+ formatNoMatches: function () { return "Нема пронајдено совпаѓања"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Ве молиме внесете уште " + n + " карактер" + (n == 1 ? "" : "и"); },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Ве молиме внесете " + n + " помалку карактер" + (n == 1? "" : "и"); },
13
+ formatSelectionTooBig: function (limit) { return "Можете да изберете само " + limit + " ставк" + (limit == 1 ? "а" : "и"); },
14
+ formatLoadMore: function (pageNumber) { return "Вчитување резултати…"; },
15
+ formatSearching: function () { return "Пребарување…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['mk']);
19
  })(jQuery);
assets/deps/select2-3.5.2/select2_locale_ms.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Malay translation.
3
- *
4
- * Author: Kepoweran <kepoweran@gmail.com>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['ms'] = {
10
- formatNoMatches: function () { return "Tiada padanan yang ditemui"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Sila masukkan " + n + " aksara lagi"; },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Sila hapuskan " + n + " aksara"; },
13
- formatSelectionTooBig: function (limit) { return "Anda hanya boleh memilih " + limit + " pilihan"; },
14
- formatLoadMore: function (pageNumber) { return "Sedang memuatkan keputusan…"; },
15
- formatSearching: function () { return "Mencari…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['ms']);
19
- })(jQuery);
1
+ /**
2
+ * Select2 Malay translation.
3
+ *
4
+ * Author: Kepoweran <kepoweran@gmail.com>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['ms'] = {
10
+ formatNoMatches: function () { return "Tiada padanan yang ditemui"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Sila masukkan " + n + " aksara lagi"; },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Sila hapuskan " + n + " aksara"; },
13
+ formatSelectionTooBig: function (limit) { return "Anda hanya boleh memilih " + limit + " pilihan"; },
14
+ formatLoadMore: function (pageNumber) { return "Sedang memuatkan keputusan…"; },
15
+ formatSearching: function () { return "Mencari…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['ms']);
19
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_nb.js CHANGED
@@ -1,22 +1,22 @@
1
- /**
2
- * Select2 Norwegian Bokmål translation.
3
- *
4
- * Author: Torgeir Veimo <torgeir.veimo@gmail.com>
5
- * Author: Bjørn Johansen <post@bjornjohansen.no>
6
- */
7
- (function ($) {
8
- "use strict";
9
-
10
- $.fn.select2.locales['nb'] = {
11
- formatMatches: function (matches) { if (matches === 1) { return "Ett resultat er tilgjengelig, trykk enter for å velge det."; } return matches + " resultater er tilgjengelig. Bruk piltastene opp og ned for å navigere."; },
12
- formatNoMatches: function () { return "Ingen treff"; },
13
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Vennligst skriv inn " + n + (n>1 ? " flere tegn" : " tegn til"); },
14
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Vennligst fjern " + n + " tegn"; },
15
- formatSelectionTooBig: function (limit) { return "Du kan velge maks " + limit + " elementer"; },
16
- formatLoadMore: function (pageNumber) { return "Laster flere resultater …"; },
17
- formatSearching: function () { return "Søker …"; }
18
- };
19
-
20
- $.extend($.fn.select2.defaults, $.fn.select2.locales['no']);
21
- })(jQuery);
22
-
1
+ /**
2
+ * Select2 Norwegian Bokmål translation.
3
+ *
4
+ * Author: Torgeir Veimo <torgeir.veimo@gmail.com>
5
+ * Author: Bjørn Johansen <post@bjornjohansen.no>
6
+ */
7
+ (function ($) {
8
+ "use strict";
9
+
10
+ $.fn.select2.locales['nb'] = {
11
+ formatMatches: function (matches) { if (matches === 1) { return "Ett resultat er tilgjengelig, trykk enter for å velge det."; } return matches + " resultater er tilgjengelig. Bruk piltastene opp og ned for å navigere."; },
12
+ formatNoMatches: function () { return "Ingen treff"; },
13
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Vennligst skriv inn " + n + (n>1 ? " flere tegn" : " tegn til"); },
14
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Vennligst fjern " + n + " tegn"; },
15
+ formatSelectionTooBig: function (limit) { return "Du kan velge maks " + limit + " elementer"; },
16
+ formatLoadMore: function (pageNumber) { return "Laster flere resultater …"; },
17
+ formatSearching: function () { return "Søker …"; }
18
+ };
19
+
20
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['no']);
21
+ })(jQuery);
22
+
assets/deps/select2-3.5.2/select2_locale_nl.js CHANGED
@@ -1,17 +1,17 @@
1
- /**
2
- * Select2 Dutch translation
3
- */
4
- (function ($) {
5
- "use strict";
6
-
7
- $.fn.select2.locales['nl'] = {
8
- formatNoMatches: function () { return "Geen resultaten gevonden"; },
9
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Vul nog " + n + " karakter" + (n == 1? "" : "s") + " in"; },
10
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Haal " + n + " karakter" + (n == 1? "" : "s") + " weg"; },
11
- formatSelectionTooBig: function (limit) { return "Maximaal " + limit + " item" + (limit == 1 ? "" : "s") + " toegestaan"; },
12
- formatLoadMore: function (pageNumber) { return "Meer resultaten laden…"; },
13
- formatSearching: function () { return "Zoeken…"; }
14
- };
15
-
16
- $.extend($.fn.select2.defaults, $.fn.select2.locales['nl']);
17
- })(jQuery);
1
+ /**
2
+ * Select2 Dutch translation
3
+ */
4
+ (function ($) {
5
+ "use strict";
6
+
7
+ $.fn.select2.locales['nl'] = {
8
+ formatNoMatches: function () { return "Geen resultaten gevonden"; },
9
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Vul nog " + n + " karakter" + (n == 1? "" : "s") + " in"; },
10
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Haal " + n + " karakter" + (n == 1? "" : "s") + " weg"; },
11
+ formatSelectionTooBig: function (limit) { return "Maximaal " + limit + " item" + (limit == 1 ? "" : "s") + " toegestaan"; },
12
+ formatLoadMore: function (pageNumber) { return "Meer resultaten laden…"; },
13
+ formatSearching: function () { return "Zoeken…"; }
14
+ };
15
+
16
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['nl']);
17
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_pl.js CHANGED
@@ -1,54 +1,54 @@
1
- /**
2
- * Select2 Polish translation.
3
- *
4
- * @author Jan Kondratowicz <jan@kondratowicz.pl>
5
- * @author Uriy Efremochkin <efremochkin@uriy.me>
6
- * @author Michał Połtyn <mike@poltyn.com>
7
- * @author Damian Zajkowski <damian.zajkowski@gmail.com>
8
- */
9
- (function($) {
10
- "use strict";
11
-
12
- $.fn.select2.locales['pl'] = {
13
- formatNoMatches: function() {
14
- return "Brak wyników";
15
- },
16
- formatInputTooShort: function(input, min) {
17
- return "Wpisz co najmniej" + character(min - input.length, "znak", "i");
18
- },
19
- formatInputTooLong: function(input, max) {
20
- return "Wpisana fraza jest za długa o" + character(input.length - max, "znak", "i");
21
- },
22
- formatSelectionTooBig: function(limit) {
23
- return "Możesz zaznaczyć najwyżej" + character(limit, "element", "y");
24
- },
25
- formatLoadMore: function(pageNumber) {
26
- return "Ładowanie wyników…";
27
- },
28
- formatSearching: function() {
29
- return "Szukanie…";
30
- }
31
- };
32
-
33
- $.extend($.fn.select2.defaults, $.fn.select2.locales['pl']);
34
-
35
- function character(n, word, pluralSuffix) {
36
- //Liczba pojedyncza - brak suffiksu
37
- //jeden znak
38
- //jeden element
39
- var suffix = '';
40
- if (n > 1 && n < 5) {
41
- //Liczaba mnoga ilość od 2 do 4 - własny suffiks
42
- //Dwa znaki, trzy znaki, cztery znaki.
43
- //Dwa elementy, trzy elementy, cztery elementy
44
- suffix = pluralSuffix;
45
- } else if (n == 0 || n >= 5) {
46
- //Ilość 0 suffiks ów
47
- //Liczaba mnoga w ilości 5 i więcej - suffiks ów (nie poprawny dla wszystkich wyrazów, np. 100 wiadomości)
48
- //Zero znaków, Pięć znaków, sześć znaków, siedem znaków, osiem znaków.
49
- //Zero elementów Pięć elementów, sześć elementów, siedem elementów, osiem elementów.
50
- suffix = 'ów';
51
- }
52
- return " " + n + " " + word + suffix;
53
- }
54
- })(jQuery);
1
+ /**
2
+ * Select2 Polish translation.
3
+ *
4
+ * @author Jan Kondratowicz <jan@kondratowicz.pl>
5
+ * @author Uriy Efremochkin <efremochkin@uriy.me>
6
+ * @author Michał Połtyn <mike@poltyn.com>
7
+ * @author Damian Zajkowski <damian.zajkowski@gmail.com>
8
+ */
9
+ (function($) {
10
+ "use strict";
11
+
12
+ $.fn.select2.locales['pl'] = {
13
+ formatNoMatches: function() {
14
+ return "Brak wyników";
15
+ },
16
+ formatInputTooShort: function(input, min) {
17
+ return "Wpisz co najmniej" + character(min - input.length, "znak", "i");
18
+ },
19
+ formatInputTooLong: function(input, max) {
20
+ return "Wpisana fraza jest za długa o" + character(input.length - max, "znak", "i");
21
+ },
22
+ formatSelectionTooBig: function(limit) {
23
+ return "Możesz zaznaczyć najwyżej" + character(limit, "element", "y");
24
+ },
25
+ formatLoadMore: function(pageNumber) {
26
+ return "Ładowanie wyników…";
27
+ },
28
+ formatSearching: function() {
29
+ return "Szukanie…";
30
+ }
31
+ };
32
+
33
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['pl']);
34
+
35
+ function character(n, word, pluralSuffix) {
36
+ //Liczba pojedyncza - brak suffiksu
37
+ //jeden znak
38
+ //jeden element
39
+ var suffix = '';
40
+ if (n > 1 && n < 5) {
41
+ //Liczaba mnoga ilość od 2 do 4 - własny suffiks
42
+ //Dwa znaki, trzy znaki, cztery znaki.
43
+ //Dwa elementy, trzy elementy, cztery elementy
44
+ suffix = pluralSuffix;
45
+ } else if (n == 0 || n >= 5) {
46
+ //Ilość 0 suffiks ów
47
+ //Liczaba mnoga w ilości 5 i więcej - suffiks ów (nie poprawny dla wszystkich wyrazów, np. 100 wiadomości)
48
+ //Zero znaków, Pięć znaków, sześć znaków, siedem znaków, osiem znaków.
49
+ //Zero elementów Pięć elementów, sześć elementów, siedem elementów, osiem elementów.
50
+ suffix = 'ów';
51
+ }
52
+ return " " + n + " " + word + suffix;
53
+ }
54
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_pt-BR.js CHANGED
@@ -1,18 +1,18 @@
1
- /**
2
- * Select2 Brazilian Portuguese translation
3
- */
4
- (function ($) {
5
- "use strict";
6
-
7
- $.fn.select2.locales['pt-BR'] = {
8
- formatNoMatches: function () { return "Nenhum resultado encontrado"; },
9
- formatAjaxError: function () { return "Erro na busca"; },
10
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Digite " + (min == 1 ? "" : "mais") + " " + n + " caracter" + (n == 1? "" : "es"); },
11
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Apague " + n + " caracter" + (n == 1? "" : "es"); },
12
- formatSelectionTooBig: function (limit) { return "Só é possível selecionar " + limit + " elemento" + (limit == 1 ? "" : "s"); },
13
- formatLoadMore: function (pageNumber) { return "Carregando mais resultados…"; },
14
- formatSearching: function () { return "Buscando…"; }
15
- };
16
-
17
- $.extend($.fn.select2.defaults, $.fn.select2.locales['pt-BR']);
18
- })(jQuery);
1
+ /**
2
+ * Select2 Brazilian Portuguese translation
3
+ */
4
+ (function ($) {
5
+ "use strict";
6
+
7
+ $.fn.select2.locales['pt-BR'] = {
8
+ formatNoMatches: function () { return "Nenhum resultado encontrado"; },
9
+ formatAjaxError: function () { return "Erro na busca"; },
10
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Digite " + (min == 1 ? "" : "mais") + " " + n + " caracter" + (n == 1? "" : "es"); },
11
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Apague " + n + " caracter" + (n == 1? "" : "es"); },
12
+ formatSelectionTooBig: function (limit) { return "Só é possível selecionar " + limit + " elemento" + (limit == 1 ? "" : "s"); },
13
+ formatLoadMore: function (pageNumber) { return "Carregando mais resultados…"; },
14
+ formatSearching: function () { return "Buscando…"; }
15
+ };
16
+
17
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['pt-BR']);
18
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_pt-PT.js CHANGED
@@ -1,17 +1,17 @@
1
- /**
2
- * Select2 Portuguese (Portugal) translation
3
- */
4
- (function ($) {
5
- "use strict";
6
-
7
- $.fn.select2.locales['pt-PT'] = {
8
- formatNoMatches: function () { return "Nenhum resultado encontrado"; },
9
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Introduza " + n + " car" + (n == 1 ? "ácter" : "acteres"); },
10
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Apague " + n + " car" + (n == 1 ? "ácter" : "acteres"); },
11
- formatSelectionTooBig: function (limit) { return "Só é possível selecionar " + limit + " elemento" + (limit == 1 ? "" : "s"); },
12
- formatLoadMore: function (pageNumber) { return "A carregar mais resultados…"; },
13
- formatSearching: function () { return "A pesquisar…"; }
14
- };
15
-
16
- $.extend($.fn.select2.defaults, $.fn.select2.locales['pt-PT']);
17
- })(jQuery);
1
+ /**
2
+ * Select2 Portuguese (Portugal) translation
3
+ */
4
+ (function ($) {
5
+ "use strict";
6
+
7
+ $.fn.select2.locales['pt-PT'] = {
8
+ formatNoMatches: function () { return "Nenhum resultado encontrado"; },
9
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Introduza " + n + " car" + (n == 1 ? "ácter" : "acteres"); },
10
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Apague " + n + " car" + (n == 1 ? "ácter" : "acteres"); },
11
+ formatSelectionTooBig: function (limit) { return "Só é possível selecionar " + limit + " elemento" + (limit == 1 ? "" : "s"); },
12
+ formatLoadMore: function (pageNumber) { return "A carregar mais resultados…"; },
13
+ formatSearching: function () { return "A pesquisar…"; }
14
+ };
15
+
16
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['pt-PT']);
17
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_ro.js CHANGED
@@ -1,17 +1,17 @@
1
- /**
2
- * Select2 Romanian translation.
3
- */
4
- (function ($) {
5
- "use strict";
6
-
7
- $.fn.select2.locales['ro'] = {
8
- formatNoMatches: function () { return "Nu a fost găsit nimic"; },
9
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Vă rugăm să introduceți incă " + n + " caracter" + (n == 1 ? "" : "e"); },
10
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Vă rugăm să introduceți mai puțin de " + n + " caracter" + (n == 1? "" : "e"); },
11
- formatSelectionTooBig: function (limit) { return "Aveți voie să selectați cel mult " + limit + " element" + (limit == 1 ? "" : "e"); },
12
- formatLoadMore: function (pageNumber) { return "Se încarcă…"; },
13
- formatSearching: function () { return "Căutare…"; }
14
- };
15
-
16
- $.extend($.fn.select2.defaults, $.fn.select2.locales['ro']);
17
- })(jQuery);
1
+ /**
2
+ * Select2 Romanian translation.
3
+ */
4
+ (function ($) {
5
+ "use strict";
6
+
7
+ $.fn.select2.locales['ro'] = {
8
+ formatNoMatches: function () { return "Nu a fost găsit nimic"; },
9
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Vă rugăm să introduceți incă " + n + " caracter" + (n == 1 ? "" : "e"); },
10
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Vă rugăm să introduceți mai puțin de " + n + " caracter" + (n == 1? "" : "e"); },
11
+ formatSelectionTooBig: function (limit) { return "Aveți voie să selectați cel mult " + limit + " element" + (limit == 1 ? "" : "e"); },
12
+ formatLoadMore: function (pageNumber) { return "Se încarcă…"; },
13
+ formatSearching: function () { return "Căutare…"; }
14
+ };
15
+
16
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['ro']);
17
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_rs.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Serbian translation.
3
- *
4
- * @author Limon Monte <limon.monte@gmail.com>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['rs'] = {
10
- formatNoMatches: function () { return "Ništa nije pronađeno"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Ukucajte bar još " + n + " simbol" + (n % 10 == 1 && n % 100 != 11 ? "" : "a"); },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Obrišite " + n + " simbol" + (n % 10 == 1 && n % 100 != 11 ? "" : "a"); },
13
- formatSelectionTooBig: function (limit) { return "Možete izabrati samo " + limit + " stavk" + (limit % 10 == 1 && limit % 100 != 11 ? "u" : (limit % 10 >= 2 && limit % 10 <= 4 && (limit % 100 < 12 || limit % 100 > 14)? "e" : "i")); },
14
- formatLoadMore: function (pageNumber) { return "Preuzimanje još rezultata…"; },
15
- formatSearching: function () { return "Pretraga…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['rs']);
19
- })(jQuery);
1
+ /**
2
+ * Select2 Serbian translation.
3
+ *
4
+ * @author Limon Monte <limon.monte@gmail.com>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['rs'] = {
10
+ formatNoMatches: function () { return "Ništa nije pronađeno"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Ukucajte bar još " + n + " simbol" + (n % 10 == 1 && n % 100 != 11 ? "" : "a"); },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Obrišite " + n + " simbol" + (n % 10 == 1 && n % 100 != 11 ? "" : "a"); },
13
+ formatSelectionTooBig: function (limit) { return "Možete izabrati samo " + limit + " stavk" + (limit % 10 == 1 && limit % 100 != 11 ? "u" : (limit % 10 >= 2 && limit % 10 <= 4 && (limit % 100 < 12 || limit % 100 > 14)? "e" : "i")); },
14
+ formatLoadMore: function (pageNumber) { return "Preuzimanje još rezultata…"; },
15
+ formatSearching: function () { return "Pretraga…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['rs']);
19
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_ru.js CHANGED
@@ -1,23 +1,23 @@
1
- /**
2
- * Select2 Russian translation.
3
- *
4
- * @author Uriy Efremochkin <efremochkin@uriy.me>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['ru'] = {
10
- formatNoMatches: function () { return "Совпадений не найдено"; },
11
- formatInputTooShort: function (input, min) { return "Пожалуйста, введите еще хотя бы" + character(min - input.length); },
12
- formatInputTooLong: function (input, max) { return "Пожалуйста, введите на" + character(input.length - max) + " меньше"; },
13
- formatSelectionTooBig: function (limit) { return "Вы можете выбрать не более " + limit + " элемент" + (limit%10 == 1 && limit%100 != 11 ? "а" : "ов"); },
14
- formatLoadMore: function (pageNumber) { return "Загрузка данных…"; },
15
- formatSearching: function () { return "Поиск…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['ru']);
19
-
20
- function character (n) {
21
- return " " + n + " символ" + (n%10 < 5 && n%10 > 0 && (n%100 < 5 || n%100 > 20) ? n%10 > 1 ? "a" : "" : "ов");
22
- }
23
- })(jQuery);
1
+ /**
2
+ * Select2 Russian translation.
3
+ *
4
+ * @author Uriy Efremochkin <efremochkin@uriy.me>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['ru'] = {
10
+ formatNoMatches: function () { return "Совпадений не найдено"; },
11
+ formatInputTooShort: function (input, min) { return "Пожалуйста, введите еще хотя бы" + character(min - input.length); },
12
+ formatInputTooLong: function (input, max) { return "Пожалуйста, введите на" + character(input.length - max) + " меньше"; },
13
+ formatSelectionTooBig: function (limit) { return "Вы можете выбрать не более " + limit + " элемент" + (limit%10 == 1 && limit%100 != 11 ? "а" : "ов"); },
14
+ formatLoadMore: function (pageNumber) { return "Загрузка данных…"; },
15
+ formatSearching: function () { return "Поиск…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['ru']);
19
+
20
+ function character (n) {
21
+ return " " + n + " символ" + (n%10 < 5 && n%10 > 0 && (n%100 < 5 || n%100 > 20) ? n%10 > 1 ? "a" : "" : "ов");
22
+ }
23
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_sk.js CHANGED
@@ -1,50 +1,50 @@
1
- /**
2
- * Select2 Slovak translation.
3
- *
4
- * Author: David Vallner <david@vallner.net>
5
- */
6
- (function ($) {
7
- "use strict";
8
- // use text for the numbers 2 through 4
9
- var smallNumbers = {
10
- 2: function(masc) { return (masc ? "dva" : "dve"); },
11
- 3: function() { return "tri"; },
12
- 4: function() { return "štyri"; }
13
- };
14
- $.fn.select2.locales['sk'] = {
15
- formatNoMatches: function () { return "Nenašli sa žiadne položky"; },
16
- formatInputTooShort: function (input, min) {
17
- var n = min - input.length;
18
- if (n == 1) {
19
- return "Prosím, zadajte ešte jeden znak";
20
- } else if (n <= 4) {
21
- return "Prosím, zadajte ešte ďalšie "+smallNumbers[n](true)+" znaky";
22
- } else {
23
- return "Prosím, zadajte ešte ďalších "+n+" znakov";
24
- }
25
- },
26
- formatInputTooLong: function (input, max) {
27
- var n = input.length - max;
28
- if (n == 1) {
29
- return "Prosím, zadajte o jeden znak menej";
30
- } else if (n >= 2 && n <= 4) {
31
- return "Prosím, zadajte o "+smallNumbers[n](true)+" znaky menej";
32
- } else {
33
- return "Prosím, zadajte o "+n+" znakov menej";
34
- }
35
- },
36
- formatSelectionTooBig: function (limit) {
37
- if (limit == 1) {
38
- return "Môžete zvoliť len jednu položku";
39
- } else if (limit >= 2 && limit <= 4) {
40
- return "Môžete zvoliť najviac "+smallNumbers[limit](false)+" položky";
41
- } else {
42
- return "Môžete zvoliť najviac "+limit+" položiek";
43
- }
44
- },
45
- formatLoadMore: function (pageNumber) { return "Načítavajú sa ďalšie výsledky…"; },
46
- formatSearching: function () { return "Vyhľadávanie…"; }
47
- };
48
-
49
- $.extend($.fn.select2.defaults, $.fn.select2.locales['sk']);
50
- })(jQuery);
1
+ /**
2
+ * Select2 Slovak translation.
3
+ *
4
+ * Author: David Vallner <david@vallner.net>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+ // use text for the numbers 2 through 4
9
+ var smallNumbers = {
10
+ 2: function(masc) { return (masc ? "dva" : "dve"); },
11
+ 3: function() { return "tri"; },
12
+ 4: function() { return "štyri"; }
13
+ };
14
+ $.fn.select2.locales['sk'] = {
15
+ formatNoMatches: function () { return "Nenašli sa žiadne položky"; },
16
+ formatInputTooShort: function (input, min) {
17
+ var n = min - input.length;
18
+ if (n == 1) {
19
+ return "Prosím, zadajte ešte jeden znak";
20
+ } else if (n <= 4) {
21
+ return "Prosím, zadajte ešte ďalšie "+smallNumbers[n](true)+" znaky";
22
+ } else {
23
+ return "Prosím, zadajte ešte ďalších "+n+" znakov";
24
+ }
25
+ },
26
+ formatInputTooLong: function (input, max) {
27
+ var n = input.length - max;
28
+ if (n == 1) {
29
+ return "Prosím, zadajte o jeden znak menej";
30
+ } else if (n >= 2 && n <= 4) {
31
+ return "Prosím, zadajte o "+smallNumbers[n](true)+" znaky menej";
32
+ } else {
33
+ return "Prosím, zadajte o "+n+" znakov menej";
34
+ }
35
+ },
36
+ formatSelectionTooBig: function (limit) {
37
+ if (limit == 1) {
38
+ return "Môžete zvoliť len jednu položku";
39
+ } else if (limit >= 2 && limit <= 4) {
40
+ return "Môžete zvoliť najviac "+smallNumbers[limit](false)+" položky";
41
+ } else {
42
+ return "Môžete zvoliť najviac "+limit+" položiek";
43
+ }
44
+ },
45
+ formatLoadMore: function (pageNumber) { return "Načítavajú sa ďalšie výsledky…"; },
46
+ formatSearching: function () { return "Vyhľadávanie…"; }
47
+ };
48
+
49
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['sk']);
50
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_sv.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Swedish translation.
3
- *
4
- * Author: Jens Rantil <jens.rantil@telavox.com>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['sv'] = {
10
- formatNoMatches: function () { return "Inga träffar"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Var god skriv in " + n + (n>1 ? " till tecken" : " tecken till"); },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Var god sudda ut " + n + " tecken"; },
13
- formatSelectionTooBig: function (limit) { return "Du kan max välja " + limit + " element"; },
14
- formatLoadMore: function (pageNumber) { return "Laddar fler resultat…"; },
15
- formatSearching: function () { return "Söker…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['sv']);
19
- })(jQuery);
1
+ /**
2
+ * Select2 Swedish translation.
3
+ *
4
+ * Author: Jens Rantil <jens.rantil@telavox.com>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['sv'] = {
10
+ formatNoMatches: function () { return "Inga träffar"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Var god skriv in " + n + (n>1 ? " till tecken" : " tecken till"); },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Var god sudda ut " + n + " tecken"; },
13
+ formatSelectionTooBig: function (limit) { return "Du kan max välja " + limit + " element"; },
14
+ formatLoadMore: function (pageNumber) { return "Laddar fler resultat…"; },
15
+ formatSearching: function () { return "Söker…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['sv']);
19
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_th.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Thai translation.
3
- *
4
- * Author: Atsawin Chaowanakritsanakul <joke@nakhon.net>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['th'] = {
10
- formatNoMatches: function () { return "ไม่พบข้อมูล"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "โปรดพิมพ์เพิ่มอีก " + n + " ตัวอักษร"; },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return "โปรดลบออก " + n + " ตัวอักษร"; },
13
- formatSelectionTooBig: function (limit) { return "คุณสามารถเลือกได้ไม่เกิน " + limit + " รายการ"; },
14
- formatLoadMore: function (pageNumber) { return "กำลังค้นข้อมูลเพิ่ม…"; },
15
- formatSearching: function () { return "กำลังค้นข้อมูล…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['th']);
19
- })(jQuery);
1
+ /**
2
+ * Select2 Thai translation.
3
+ *
4
+ * Author: Atsawin Chaowanakritsanakul <joke@nakhon.net>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['th'] = {
10
+ formatNoMatches: function () { return "ไม่พบข้อมูล"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "โปรดพิมพ์เพิ่มอีก " + n + " ตัวอักษร"; },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "โปรดลบออก " + n + " ตัวอักษร"; },
13
+ formatSelectionTooBig: function (limit) { return "คุณสามารถเลือกได้ไม่เกิน " + limit + " รายการ"; },
14
+ formatLoadMore: function (pageNumber) { return "กำลังค้นข้อมูลเพิ่ม…"; },
15
+ formatSearching: function () { return "กำลังค้นข้อมูล…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['th']);
19
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_tr.js CHANGED
@@ -1,19 +1,19 @@
1
- /**
2
- * Select2 Turkish translation.
3
- *
4
- * Author: Salim KAYABAŞI <salim.kayabasi@gmail.com>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['tr'] = {
10
- formatNoMatches: function () { return "Sonuç bulunamadı"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "En az " + n + " karakter daha girmelisiniz"; },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return n + " karakter azaltmalısınız"; },
13
- formatSelectionTooBig: function (limit) { return "Sadece " + limit + " seçim yapabilirsiniz"; },
14
- formatLoadMore: function (pageNumber) { return "Daha fazla…"; },
15
- formatSearching: function () { return "Aranıyor…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['tr']);
19
- })(jQuery);
1
+ /**
2
+ * Select2 Turkish translation.
3
+ *
4
+ * Author: Salim KAYABAŞI <salim.kayabasi@gmail.com>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['tr'] = {
10
+ formatNoMatches: function () { return "Sonuç bulunamadı"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "En az " + n + " karakter daha girmelisiniz"; },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return n + " karakter azaltmalısınız"; },
13
+ formatSelectionTooBig: function (limit) { return "Sadece " + limit + " seçim yapabilirsiniz"; },
14
+ formatLoadMore: function (pageNumber) { return "Daha fazla…"; },
15
+ formatSearching: function () { return "Aranıyor…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['tr']);
19
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_ug-CN.js CHANGED
@@ -1,16 +1,16 @@
1
- /**
2
- * Select2 Uyghur translation
3
- */
4
- (function ($) {
5
- "use strict";
6
- $.fn.select2.locales['ug-CN'] = {
7
- formatNoMatches: function () { return "ماس كېلىدىغان ئۇچۇر تېپىلمىدى"; },
8
- formatInputTooShort: function (input, min) { var n = min - input.length; return "يەنە " + n + " ھەرپ كىرگۈزۈڭ";},
9
- formatInputTooLong: function (input, max) { var n = input.length - max; return "" + n + "ھەرپ ئۆچۈرۈڭ";},
10
- formatSelectionTooBig: function (limit) { return "ئەڭ كۆپ بولغاندا" + limit + " تال ئۇچۇر تاللىيالايسىز"; },
11
- formatLoadMore: function (pageNumber) { return "ئۇچۇرلار ئوقۇلىۋاتىدۇ…"; },
12
- formatSearching: function () { return "ئىزدەۋاتىدۇ…"; }
13
- };
14
-
15
- $.extend($.fn.select2.defaults, $.fn.select2.locales['ug-CN']);
16
- })(jQuery);
1
+ /**
2
+ * Select2 Uyghur translation
3
+ */
4
+ (function ($) {
5
+ "use strict";
6
+ $.fn.select2.locales['ug-CN'] = {
7
+ formatNoMatches: function () { return "ماس كېلىدىغان ئۇچۇر تېپىلمىدى"; },
8
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "يەنە " + n + " ھەرپ كىرگۈزۈڭ";},
9
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "" + n + "ھەرپ ئۆچۈرۈڭ";},
10
+ formatSelectionTooBig: function (limit) { return "ئەڭ كۆپ بولغاندا" + limit + " تال ئۇچۇر تاللىيالايسىز"; },
11
+ formatLoadMore: function (pageNumber) { return "ئۇچۇرلار ئوقۇلىۋاتىدۇ…"; },
12
+ formatSearching: function () { return "ئىزدەۋاتىدۇ…"; }
13
+ };
14
+
15
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['ug-CN']);
16
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_uk.js CHANGED
@@ -1,25 +1,25 @@
1
- /**
2
- * Select2 Ukrainian translation.
3
- *
4
- * @author bigmihail <bigmihail@bigmir.net>
5
- * @author Uriy Efremochkin <efremochkin@uriy.me>
6
- */
7
- (function ($) {
8
- "use strict";
9
-
10
- $.fn.select2.locales['uk'] = {
11
- formatMatches: function (matches) { return character(matches, "результат") + " знайдено, використовуйте клавіші зі стрілками вверх та вниз для навігації."; },
12
- formatNoMatches: function () { return "Нічого не знайдено"; },
13
- formatInputTooShort: function (input, min) { return "Введіть буль ласка ще " + character(min - input.length, "символ"); },
14
- formatInputTooLong: function (input, max) { return "Введіть буль ласка на " + character(input.length - max, "символ") + " менше"; },
15
- formatSelectionTooBig: function (limit) { return "Ви можете вибрати лише " + character(limit, "елемент"); },
16
- formatLoadMore: function (pageNumber) { return "Завантаження даних…"; },
17
- formatSearching: function () { return "Пошук…"; }
18
- };
19
-
20
- $.extend($.fn.select2.defaults, $.fn.select2.locales['uk']);
21
-
22
- function character (n, word) {
23
- return n + " " + word + (n%10 < 5 && n%10 > 0 && (n%100 < 5 || n%100 > 19) ? n%10 > 1 ? "и" : "" : "ів");
24
- }
25
- })(jQuery);
1
+ /**
2
+ * Select2 Ukrainian translation.
3
+ *
4
+ * @author bigmihail <bigmihail@bigmir.net>
5
+ * @author Uriy Efremochkin <efremochkin@uriy.me>
6
+ */
7
+ (function ($) {
8
+ "use strict";
9
+
10
+ $.fn.select2.locales['uk'] = {
11
+ formatMatches: function (matches) { return character(matches, "результат") + " знайдено, використовуйте клавіші зі стрілками вверх та вниз для навігації."; },
12
+ formatNoMatches: function () { return "Нічого не знайдено"; },
13
+ formatInputTooShort: function (input, min) { return "Введіть буль ласка ще " + character(min - input.length, "символ"); },
14
+ formatInputTooLong: function (input, max) { return "Введіть буль ласка на " + character(input.length - max, "символ") + " менше"; },
15
+ formatSelectionTooBig: function (limit) { return "Ви можете вибрати лише " + character(limit, "елемент"); },
16
+ formatLoadMore: function (pageNumber) { return "Завантаження даних…"; },
17
+ formatSearching: function () { return "Пошук…"; }
18
+ };
19
+
20
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['uk']);
21
+
22
+ function character (n, word) {
23
+ return n + " " + word + (n%10 < 5 && n%10 > 0 && (n%100 < 5 || n%100 > 19) ? n%10 > 1 ? "и" : "" : "ів");
24
+ }
25
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_vi.js CHANGED
@@ -1,20 +1,20 @@
1
- /**
2
- * Select2 Vietnamese translation.
3
- *
4
- * Author: Long Nguyen <olragon@gmail.com>
5
- */
6
- (function ($) {
7
- "use strict";
8
-
9
- $.fn.select2.locales['vi'] = {
10
- formatNoMatches: function () { return "Không tìm thấy kết quả"; },
11
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Vui lòng nhập nhiều hơn " + n + " ký tự" + (n == 1 ? "" : "s"); },
12
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Vui lòng nhập ít hơn " + n + " ký tự" + (n == 1? "" : "s"); },
13
- formatSelectionTooBig: function (limit) { return "Chỉ có thể chọn được " + limit + " tùy chọn" + (limit == 1 ? "" : "s"); },
14
- formatLoadMore: function (pageNumber) { return "Đang lấy thêm kết quả…"; },
15
- formatSearching: function () { return "Đang tìm…"; }
16
- };
17
-
18
- $.extend($.fn.select2.defaults, $.fn.select2.locales['vi']);
19
- })(jQuery);
20
-
1
+ /**
2
+ * Select2 Vietnamese translation.
3
+ *
4
+ * Author: Long Nguyen <olragon@gmail.com>
5
+ */
6
+ (function ($) {
7
+ "use strict";
8
+
9
+ $.fn.select2.locales['vi'] = {
10
+ formatNoMatches: function () { return "Không tìm thấy kết quả"; },
11
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Vui lòng nhập nhiều hơn " + n + " ký tự" + (n == 1 ? "" : "s"); },
12
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Vui lòng nhập ít hơn " + n + " ký tự" + (n == 1? "" : "s"); },
13
+ formatSelectionTooBig: function (limit) { return "Chỉ có thể chọn được " + limit + " tùy chọn" + (limit == 1 ? "" : "s"); },
14
+ formatLoadMore: function (pageNumber) { return "Đang lấy thêm kết quả…"; },
15
+ formatSearching: function () { return "Đang tìm…"; }
16
+ };
17
+
18
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['vi']);
19
+ })(jQuery);
20
+
assets/deps/select2-3.5.2/select2_locale_zh-CN.js CHANGED
@@ -1,16 +1,16 @@
1
- /**
2
- * Select2 Chinese translation
3
- */
4
- (function ($) {
5
- "use strict";
6
- $.fn.select2.locales['zh-CN'] = {
7
- formatNoMatches: function () { return "没有找到匹配项"; },
8
- formatInputTooShort: function (input, min) { var n = min - input.length; return "请再输入" + n + "个字符";},
9
- formatInputTooLong: function (input, max) { var n = input.length - max; return "请删掉" + n + "个字符";},
10
- formatSelectionTooBig: function (limit) { return "你只能选择最多" + limit + "项"; },
11
- formatLoadMore: function (pageNumber) { return "加载结果中…"; },
12
- formatSearching: function () { return "搜索中…"; }
13
- };
14
-
15
- $.extend($.fn.select2.defaults, $.fn.select2.locales['zh-CN']);
16
- })(jQuery);
1
+ /**
2
+ * Select2 Chinese translation
3
+ */
4
+ (function ($) {
5
+ "use strict";
6
+ $.fn.select2.locales['zh-CN'] = {
7
+ formatNoMatches: function () { return "没有找到匹配项"; },
8
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "请再输入" + n + "个字符";},
9
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "请删掉" + n + "个字符";},
10
+ formatSelectionTooBig: function (limit) { return "你只能选择最多" + limit + "项"; },
11
+ formatLoadMore: function (pageNumber) { return "加载结果中…"; },
12
+ formatSearching: function () { return "搜索中…"; }
13
+ };
14
+
15
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['zh-CN']);
16
+ })(jQuery);
assets/deps/select2-3.5.2/select2_locale_zh-TW.js CHANGED
@@ -1,16 +1,16 @@
1
- /**
2
- * Select2 Traditional Chinese translation
3
- */
4
- (function ($) {
5
- "use strict";
6
- $.fn.select2.locales['zh-TW'] = {
7
- formatNoMatches: function () { return "沒有找到相符的項目"; },
8
- formatInputTooShort: function (input, min) { var n = min - input.length; return "請再輸入" + n + "個字元";},
9
- formatInputTooLong: function (input, max) { var n = input.length - max; return "請刪掉" + n + "個字元";},
10
- formatSelectionTooBig: function (limit) { return "你只能選擇最多" + limit + "項"; },
11
- formatLoadMore: function (pageNumber) { return "載入中…"; },
12
- formatSearching: function () { return "搜尋中…"; }
13
- };
14
-
15
- $.extend($.fn.select2.defaults, $.fn.select2.locales['zh-TW']);
16
- })(jQuery);
1
+ /**
2
+ * Select2 Traditional Chinese translation
3
+ */
4
+ (function ($) {
5
+ "use strict";
6
+ $.fn.select2.locales['zh-TW'] = {
7
+ formatNoMatches: function () { return "沒有找到相符的項目"; },
8
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "請再輸入" + n + "個字元";},
9
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "請刪掉" + n + "個字元";},
10
+ formatSelectionTooBig: function (limit) { return "你只能選擇最多" + limit + "項"; },
11
+ formatLoadMore: function (pageNumber) { return "載入中…"; },
12
+ formatSearching: function () { return "搜尋中…"; }
13
+ };
14
+
15
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['zh-TW']);
16
+ })(jQuery);
assets/deps/starrr/starrr.css CHANGED
@@ -1,7 +1,7 @@
1
- .starrr {
2
- display: inline-block; }
3
- .starrr i {
4
- font-size: 16px;
5
- padding: 0 1px;
6
- cursor: pointer;
7
- color: #ffd119; }
1
+ .starrr {
2
+ display: inline-block; }
3
+ .starrr i {
4
+ font-size: 16px;
5
+ padding: 0 1px;
6
+ cursor: pointer;
7
+ color: #ffd119; }
assets/deps/starrr/starrr.js CHANGED
@@ -1,123 +1,123 @@
1
- var __slice = [].slice;
2
-
3
- (function(jQuery, window) {
4
- var Starrr;
5
- window.Starrr = Starrr = (function() {
6
- Starrr.prototype.defaults = {
7
- rating: void 0,
8
- numStars: 5,
9
- emptyStarClass: 'fa fa-star-o',
10
- fullStarClass: 'fa fa-star',
11
- change: function(e, value) {}
12
- };
13
-
14
- function Starrr($el, options) {
15
- var i, _, _ref;
16
- this.options = jQuery.extend({}, this.defaults, options);
17
- this.$el = $el;
18
- _ref = this.defaults;
19
- for (i in _ref) {
20
- _ = _ref[i];
21
- if (this.$el.data(i.toLowerCase()) != null) {
22
- this.options[i] = this.$el.data(i.toLowerCase());
23
- }
24
- }
25
- if (this.$el.data('connected-input')) {
26
- this.$connectedInput = jQuery("[name=\"" + (this.$el.data('connected-input')) + "\"]");
27
- this.options.rating = this.$connectedInput.val() ? parseInt(this.$connectedInput.val(), 10) : void 0;
28
- }
29
- this.createStars();
30
- this.syncRating();
31
- if (this.$connectedInput && this.$connectedInput.is(':disabled')) {
32
- return;
33
- }
34
- this.$el.on('mouseover.starrr', 'i', (function(_this) {
35
- return function(e) {
36
- return _this.syncRating(_this.getStars().index(e.currentTarget) + 1);
37
- };
38
- })(this));
39
- this.$el.on('mouseout.starrr', (function(_this) {
40
- return function() {
41
- return _this.syncRating();
42
- };
43
- })(this));
44
- this.$el.on('click.starrr', 'i', (function(_this) {
45
- return function(e) {
46
- return _this.setRating(_this.getStars().index(e.currentTarget) + 1);
47
- };
48
- })(this));
49
- this.$el.on('starrr:change', this.options.change);
50
- if (this.$connectedInput != null) {
51
- this.$el.on('starrr:change', (function(_this) {
52
- return function(e, value) {
53
- _this.$connectedInput.val(value);
54
- return _this.$connectedInput.trigger('focusout');
55
- };
56
- })(this));
57
- }
58
- }
59
-
60
- Starrr.prototype.getStars = function() {
61
- return this.$el.find('i');
62
- };
63
-
64
- Starrr.prototype.createStars = function() {
65
- var _i, _ref, _results;
66
- _results = [];
67
- for (_i = 1, _ref = this.options.numStars; 1 <= _ref ? _i <= _ref : _i >= _ref; 1 <= _ref ? _i++ : _i--) {
68
- _results.push(this.$el.append("<i class='" + this.options.emptyStarClass + "'></i>"));
69
- }
70
- return _results;
71
- };
72
-
73
- Starrr.prototype.setRating = function(rating) {
74
- if (this.options.rating === rating) {
75
- rating = void 0;
76
- }
77
- this.options.rating = rating;
78
- this.syncRating();
79
- return this.$el.trigger('starrr:change', rating);
80
- };
81
-
82
- Starrr.prototype.getRating = function() {
83
- return this.options.rating;
84
- };
85
-
86
- Starrr.prototype.syncRating = function(rating) {
87
- var i, _i, _j, _ref, _ref1;
88
- rating || (rating = this.options.rating);
89
- if (rating) {
90
- for (i = _i = 0, _ref = rating - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
91
- this.getStars().eq(i).removeClass(this.options.emptyStarClass).addClass(this.options.fullStarClass);
92
- }
93
- }
94
- if (rating && rating < this.options.numStars) {
95
- for (i = _j = rating, _ref1 = this.options.numStars - 1; rating <= _ref1 ? _j <= _ref1 : _j >= _ref1; i = rating <= _ref1 ? ++_j : --_j) {
96
- this.getStars().eq(i).removeClass(this.options.fullStarClass).addClass(this.options.emptyStarClass);
97
- }
98
- }
99
- if (!rating) {
100
- return this.getStars().removeClass(this.options.fullStarClass).addClass(this.options.emptyStarClass);
101
- }
102
- };
103
-
104
- return Starrr;
105
-
106
- })();
107
- return jQuery.fn.extend({
108
- starrr: function() {
109
- var args, option;
110
- option = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
111
- return this.each(function() {
112
- var data;
113
- data = jQuery(this).data('starrr');
114
- if (!data) {
115
- jQuery(this).data('starrr', (data = new Starrr(jQuery(this), option)));
116
- }
117
- if (typeof option === 'string') {
118
- return data[option].apply(data, args);
119
- }
120
- });
121
- }
122
- });
123
- })(window.jQuery, window);
1
+ var __slice = [].slice;
2
+
3
+ (function(jQuery, window) {
4
+ var Starrr;
5
+ window.Starrr = Starrr = (function() {
6
+ Starrr.prototype.defaults = {
7
+ rating: void 0,
8
+ numStars: 5,
9
+ emptyStarClass: 'fa fa-star-o',
10
+ fullStarClass: 'fa fa-star',
11
+ change: function(e, value) {}
12
+ };
13
+
14
+ function Starrr($el, options) {
15
+ var i, _, _ref;
16
+ this.options = jQuery.extend({}, this.defaults, options);
17
+ this.$el = $el;
18
+ _ref = this.defaults;
19
+ for (i in _ref) {
20
+ _ = _ref[i];
21
+ if (this.$el.data(i.toLowerCase()) != null) {
22
+ this.options[i] = this.$el.data(i.toLowerCase());
23
+ }
24
+ }
25
+ if (this.$el.data('connected-input')) {
26
+ this.$connectedInput = jQuery("[name=\"" + (this.$el.data('connected-input')) + "\"]");
27
+ this.options.rating = this.$connectedInput.val() ? parseInt(this.$connectedInput.val(), 10) : void 0;
28
+ }
29
+ this.createStars();
30
+ this.syncRating();
31
+ if (this.$connectedInput && this.$connectedInput.is(':disabled')) {
32
+ return;
33
+ }
34
+ this.$el.on('mouseover.starrr', 'i', (function(_this) {
35
+ return function(e) {
36
+ return _this.syncRating(_this.getStars().index(e.currentTarget) + 1);
37
+ };
38
+ })(this));
39
+ this.$el.on('mouseout.starrr', (function(_this) {
40
+ return function() {
41
+ return _this.syncRating();
42
+ };
43
+ })(this));
44
+ this.$el.on('click.starrr', 'i', (function(_this) {
45
+ return function(e) {
46
+ return _this.setRating(_this.getStars().index(e.currentTarget) + 1);
47
+ };
48
+ })(this));
49
+ this.$el.on('starrr:change', this.options.change);
50
+ if (this.$connectedInput != null) {
51
+ this.$el.on('starrr:change', (function(_this) {
52
+ return function(e, value) {
53
+ _this.$connectedInput.val(value);
54
+ return _this.$connectedInput.trigger('focusout');
55
+ };
56
+ })(this));
57
+ }
58
+ }
59
+
60
+ Starrr.prototype.getStars = function() {
61
+ return this.$el.find('i');
62
+ };
63
+
64
+ Starrr.prototype.createStars = function() {
65
+ var _i, _ref, _results;
66
+ _results = [];
67
+ for (_i = 1, _ref = this.options.numStars; 1 <= _ref ? _i <= _ref : _i >= _ref; 1 <= _ref ? _i++ : _i--) {
68
+ _results.push(this.$el.append("<i class='" + this.options.emptyStarClass + "'></i>"));
69
+ }
70
+ return _results;
71
+ };
72
+
73
+ Starrr.prototype.setRating = function(rating) {
74
+ if (this.options.rating === rating) {
75
+ rating = void 0;
76
+ }
77
+ this.options.rating = rating;
78
+ this.syncRating();
79
+ return this.$el.trigger('starrr:change', rating);
80
+ };
81
+
82
+ Starrr.prototype.getRating = function() {
83
+ return this.options.rating;
84
+ };
85
+
86
+ Starrr.prototype.syncRating = function(rating) {
87
+ var i, _i, _j, _ref, _ref1;
88
+ rating || (rating = this.options.rating);
89
+ if (rating) {
90
+ for (i = _i = 0, _ref = rating - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
91
+ this.getStars().eq(i).removeClass(this.options.emptyStarClass).addClass(this.options.fullStarClass);
92
+ }
93
+ }
94
+ if (rating && rating < this.options.numStars) {
95
+ for (i = _j = rating, _ref1 = this.options.numStars - 1; rating <= _ref1 ? _j <= _ref1 : _j >= _ref1; i = rating <= _ref1 ? ++_j : --_j) {
96
+ this.getStars().eq(i).removeClass(this.options.fullStarClass).addClass(this.options.emptyStarClass);
97
+ }
98
+ }
99
+ if (!rating) {
100
+ return this.getStars().removeClass(this.options.fullStarClass).addClass(this.options.emptyStarClass);
101
+ }
102
+ };
103
+
104
+ return Starrr;
105
+
106
+ })();
107
+ return jQuery.fn.extend({
108
+ starrr: function() {
109
+ var args, option;
110
+ option = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
111
+ return this.each(function() {
112
+ var data;
113
+ data = jQuery(this).data('starrr');
114
+ if (!data) {
115
+ jQuery(this).data('starrr', (data = new Starrr(jQuery(this), option)));
116
+ }
117
+ if (typeof option === 'string') {
118
+ return data[option].apply(data, args);
119
+ }
120
+ });
121
+ }
122
+ });
123
+ })(window.jQuery, window);
assets/js/library.js ADDED
@@ -0,0 +1,446 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //IntellyWP
2
+ var TCMP={};
3
+ TCMP.startsWith=function(str, prefix) {
4
+ return str.indexOf(prefix) === 0;
5
+ }
6
+ TCMP.endsWith=function(str, suffix) {
7
+ var result=false;
8
+ var pos=str.lastIndexOf(suffix);
9
+ if(pos===(str.length-suffix.length+1)) {
10
+ result=true;
11
+ }
12
+ return result;
13
+ }
14
+ TCMP.stripos=function(haystack, needle, offset) {
15
+ var haystack=(haystack + '').toLowerCase();
16
+ var needle=(needle + '').toLowerCase();
17
+ var index=0;
18
+
19
+ if ((index=haystack.indexOf(needle, offset))!==-1) {
20
+ return index;
21
+ }
22
+ return false;
23
+ };
24
+ TCMP.strpos=function(haystack, needle, offset) {
25
+ var haystack=(haystack + '');
26
+ var needle=(needle + '');
27
+ var index=0;
28
+
29
+ if ((index=haystack.indexOf(needle, offset))!==-1) {
30
+ return index;
31
+ }
32
+ return false;
33
+ };
34
+ TCMP.val=function(name, defaults) {
35
+ defaults=(defaults || '');
36
+
37
+ var result=[];
38
+ var $self=TCMP.jQuery(name);
39
+ if($self!==false) {
40
+ $self.each(function(i,v) {
41
+ var $this=jQuery(this);
42
+ var type=TCMP.attr($this, 'type', '');
43
+ if(type=='checkbox') {
44
+ v=TCMP.check($this);
45
+ } else if(type=='radio') {
46
+ v=TCMP.radio($this);
47
+ } else {
48
+ v=$this.val();
49
+ }
50
+ result.push(v);
51
+ });
52
+ }
53
+ if(result.length==0 || (result.length==1 && result[0]===null)) {
54
+ result=defaults;
55
+ } else {
56
+ result=result.join('|');
57
+ }
58
+ return result;
59
+ };
60
+ TCMP.check=function(name) {
61
+ var $self=TCMP.jQuery(name);
62
+ return ($self.is(':checked') ? 1 : 0);
63
+ };
64
+ TCMP.radio=function(name) {
65
+ var $self=TCMP.jQuery(name);
66
+ return ($self.filter(':checked').val());
67
+ };
68
+ TCMP.visible=function(name, visible) {
69
+ if(visible) {
70
+ jQuery(name).hide();
71
+ } else {
72
+ jQuery(name).show();
73
+ }
74
+ };
75
+ TCMP.aval=function(name) {
76
+ var data={};
77
+ jQuery("[name^='"+name+"']").each(function(i,v) {
78
+ var $this=jQuery(this);
79
+ var k=$this.attr('name');
80
+ var v=$this.val();
81
+ if($this.attr('type')=='checkbox') {
82
+ v=TCMP.check(k);
83
+ } else if($this.attr('type')=='radio') {
84
+ v=TCMP.radio(k);
85
+ }
86
+ data[k]=v;
87
+ });
88
+ //console.log(data);
89
+ return data;
90
+ };
91
+ TCMP.formatColorOption=function(option) {
92
+ if (!option.id) {
93
+ return option.text;
94
+ }
95
+
96
+ var color=jQuery(option.element).css('background-color');
97
+ var font=jQuery(option.element).css('color');
98
+ var $option=jQuery('<div></div>')
99
+ .html(option.text)
100
+ .css('background-color', color)
101
+ .css('color', font)
102
+ .addClass('lbColorSelectItem');
103
+ return $option;
104
+ };
105
+ TCMP.hideShow=function(name) {
106
+ var $source=TCMP.jQuery(name);
107
+ if ($source.attr('ipfm-hideIfTrue') && $source.attr('ipfm-hideShow')) {
108
+ var $destination=jQuery('[name=' + $source.attr('ipfm-hideShow') + ']');
109
+ if ($destination.length == 0) {
110
+ $destination=jQuery('#' + $source.attr('ipfm-hideShow'));
111
+ }
112
+ if ($destination.length > 0) {
113
+ var isChecked=$source.is(":checked");
114
+ var hideIfTrue=($source.attr('ipfm-hideIfTrue').toLowerCase() == 'true');
115
+
116
+ if (isChecked) {
117
+ if (hideIfTrue) {
118
+ $destination.hide();
119
+ } else {
120
+ $destination.show();
121
+ }
122
+ } else {
123
+ if (hideIfTrue) {
124
+ $destination.show();
125
+ } else {
126
+ $destination.hide();
127
+ }
128
+ }
129
+ }
130
+ }
131
+ };
132
+ TCMP.jQuery=function(name) {
133
+ var $self=name;
134
+ if(jQuery.type(name)=='string' || jQuery.type(name)=='array') {
135
+ $self=false;
136
+ var array=[];
137
+ var names=[];
138
+ switch (jQuery.type(name)) {
139
+ case 'string':
140
+ names=name.split('|');
141
+ break;
142
+ case 'array':
143
+ names=name;
144
+ break;
145
+ }
146
+ jQuery.each(names, function(i,v) {
147
+ var selector='[name='+v+']';
148
+ if(jQuery(selector).length>0) {
149
+ array.push(selector);
150
+ } else {
151
+ selector='#'+v;
152
+ if(jQuery(selector).length>0) {
153
+ array.push(selector);
154
+ }
155
+ }
156
+ });
157
+ if(array.length>0) {
158
+ array=array.join(',');
159
+ $self=jQuery(array);
160
+ }
161
+ }
162
+ return $self;
163
+ }
164
+ TCMP.attr=function($self, name, v) {
165
+ $self=TCMP.jQuery($self);
166
+ var result=v;
167
+ if($self.length>0) {
168
+ result=$self.attr(name);
169
+ }
170
+ if ((typeof result === typeof undefined) || (result===false)) {
171
+ result=v;
172
+ }
173
+ return result;
174
+ };
175
+ TCMP.select2=function($self, options) {
176
+ TCMP.destroy($self);
177
+
178
+ var $self=TCMP.jQuery($self);
179
+ var name=$self.attr('name');
180
+ var multiple=TCMP.attr($self, 'multiple', false);
181
+ if (multiple!==false) {
182
+ multiple=true;
183
+ }
184
+
185
+ hasSelection=false;
186
+ if($self.html().indexOf('selected')>0) {
187
+ //jQuery fails if you dont have any selected item return the first
188
+ $self.find("option").each(function() {
189
+ var $option=jQuery(this);
190
+ if(TCMP.attr($option, 'selected', '')!='') {
191
+ hasSelection=true;
192
+ }
193
+ });
194
+ }
195
+
196
+ var help=TCMP.attr($self, 'ipfm-help', '');
197
+ var ajax=TCMP.attr($self, 'ipfm-ajax', false);
198
+ var parent=TCMP.attr($self, 'ipfm-master', '');
199
+ var settings={};
200
+ if(ajax===false || ajax==='') {
201
+ settings={
202
+ placeholder: help
203
+ , width: '100%'
204
+ , allowClear: true
205
+ }
206
+ } else {
207
+ settings={
208
+ placeholder: help
209
+ , width: '100%'
210
+ , allowClear: true
211
+ , ajax: {
212
+ type: 'POST'
213
+ , dataType: 'json'
214
+ , delay: 250
215
+ , data: function (params) {
216
+ var result={
217
+ q: params.term
218
+ , page: params.page
219
+ , action: 'lb_ajax_ll'
220
+ , lb_action: ajax
221
+ };
222
+ if(parent!='') {
223
+ result['parentId']=TCMP.val(parent);
224
+ }
225
+ return result;
226
+ }
227
+ , processResults: function (data, page) {
228
+ return {results: data};
229
+ }
230
+ , cache: true
231
+ }
232
+ , minimumInputLength: 2
233
+ }
234
+ }
235
+ settings=jQuery.extend(settings, options);
236
+ $self.select2(settings);
237
+ $self.hide();
238
+ if(!hasSelection) {
239
+ $self.val(null).trigger('change');
240
+ }
241
+ };
242
+ TCMP.destroy=function($self) {
243
+ var name=$self.attr('name');
244
+ try {
245
+ if($self.data('select2') != null) {
246
+ //TCMP.log('[%s] DESTROY SELECT2', name);
247
+ $self.select2("destroy");
248
+ $self.html("<option><option>");
249
+ $self.val('').trigger('change');
250
+ }
251
+ } catch(ex) {}
252
+ };
253
+ TCMP.inArray=function(v, array) {
254
+ var result=false;
255
+ if(!array || !jQuery.isArray(array) || array.length==0) {
256
+ if(jQuery.type(array)=='string' && v==array) {
257
+ result=true;
258
+ }
259
+ } else {
260
+ for(i=0; i<array.length; i++) {
261
+ c=array[i];
262
+ if(v==c) {
263
+ result=true;
264
+ break;
265
+ }
266
+ }
267
+ }
268
+ return result;
269
+ }
270
+ TCMP.changeShowOptions=function($self) {
271
+ var selection=$self.val();
272
+ var name=TCMP.attr($self, 'name', '');
273
+ var $options=$self.children('option');
274
+ //console.log('NAME=[%s] OPTIONS=N.%s', name, $options.length);
275
+ var toShow={};
276
+ var toHide={};
277
+ $options.each(function(i,v) {
278
+ $option=jQuery(v);
279
+ var text=TCMP.attr($option, 'show', '');
280
+ if(text!='') {
281
+ text=text.split('|');
282
+ var j=0;
283
+ for(j=0; j<text.length; j++) {
284
+ var show=text[j];
285
+ var $show=jQuery('#'+show);
286
+ if($show.length>0) {
287
+ var value=TCMP.attr($option, 'value', '');
288
+ if(TCMP.inArray(value, selection)) {
289
+ toShow[show]=show;
290
+ } else {
291
+ toHide[show]=show;
292
+ }
293
+ } else {
294
+ console.log('changeShowOptions ID=[%s] NOT FOUND', show);
295
+ }
296
+ }
297
+ }
298
+ });
299
+
300
+ jQuery.each(toShow, function(k,v) {
301
+ delete toHide[k];
302
+ var $w=jQuery('#'+k);
303
+ $w.show();
304
+ });
305
+ jQuery.each(toHide, function(k,v) {
306
+ var $w=jQuery('#'+k);
307
+ $w.hide();
308
+ });
309
+ }
310
+ TCMP.setCookie=function(name,value,days) {
311
+ name='TCMP_'+name;
312
+ if (days) {
313
+ var date = new Date();
314
+ date.setTime(date.getTime()+(days*24*60*60*1000));
315
+ var expires = "; expires="+date.toGMTString();
316
+ }
317
+ else var expires = "";
318
+ document.cookie = name+"="+value+expires+"; path=/";
319
+ }
320
+ TCMP.getCookie=function(name) {
321
+ name='TCMP_'+name;
322
+ var nameEQ = name + "=";
323
+ var ca = document.cookie.split(';');
324
+ for(var i=0;i < ca.length;i++) {
325
+ var c = ca[i];
326
+ while (c.charAt(0)==' ') c = c.substring(1,c.length);
327
+ if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
328
+ }
329
+ return null;
330
+ }
331
+ TCMP.removeCookie=function(name) {
332
+ createCookie(name,"",-1);
333
+ }
334
+ TCMP.getDateCookie=function(name) {
335
+ var result=TCMP.getCookie(name);
336
+ if(result!==null) {
337
+ //console.log('getDateCookie RESULT=%s', result);
338
+ result=moment(result).toDate();
339
+ //console.log('getDateCookie MOMENT=%s', result);
340
+ }
341
+ return result;
342
+ }
343
+ TCMP.setDateCookie=function(name, value, days) {
344
+ if(value!==null && value!=='') {
345
+ //console.log('setDateCookie RESULT=%s', value);
346
+ value=moment(value).format();
347
+ //console.log('setDateCookie MOMENT=%s', value);
348
+ }
349
+ TCMP.setCookie(name, value, days);
350
+ }
351
+ TCMP.formatTimer=function(time) {
352
+ if(!(time+'').match(/^\d+$/)) {
353
+ if(jQuery.type(time)=='string') {
354
+ time=time.replace(' ', ':');
355
+ time=time.replace('.', ':');
356
+ time=time.replace('/', ':');
357
+ time=time.split(':');
358
+
359
+ days=0;
360
+ hours=0;
361
+ minutes=0;
362
+ var length=time.length;
363
+ secs=parseInt(time[length-1]);
364
+ if(length>1) {
365
+ minutes=parseInt(time[length-2]);
366
+ if(length>2) {
367
+ hours=parseInt(time[length-3]);
368
+ if(length>3) {
369
+ days=parseInt(time[length-4]);
370
+ }
371
+ }
372
+ }
373
+ days=(isNaN(days) ? 0 : days);
374
+ hours=(isNaN(hours) ? 0 : hours);
375
+ minutes=(isNaN(minutes) ? 0 : minutes);
376
+ secs=(isNaN(secs) ? 0 : secs);
377
+ time=days*86400+hours*3600+minutes*60+secs;
378
+ } else {
379
+ time=0;
380
+ }
381
+ } else {
382
+ time=parseInt(time);
383
+ }
384
+
385
+ secs=time%60;
386
+ time=(time-secs)/60;
387
+ minutes=time%60;
388
+ time=(time-minutes)/60;
389
+ hours=time%24;
390
+ days=(time-hours)/24;
391
+
392
+ result=[];
393
+ result.push(days);
394
+ result.push((hours<10 ? '0' : '')+hours);
395
+ result.push((minutes<10 ? '0' : '')+minutes);
396
+ result.push((secs<10 ? '0' : '')+secs);
397
+ result=result.join(':');
398
+ return result;
399
+ }
400
+ TCMP.parseTimer=function(time) {
401
+ time=TCMP.formatTimer(time);
402
+ time=time.split(':');
403
+ result=parseInt(time[0])*86400+parseInt(time[1])*3600+parseInt(time[2])*60+parseInt(time[3]);
404
+ return result;
405
+ }
406
+ TCMP.isTrue=function(value) {
407
+ var result=false;
408
+ if(value===true) {
409
+ result=true;
410
+ } else if(value===false) {
411
+ result=false;
412
+ } else {
413
+ value=(value+'').toLowerCase();
414
+ result=(value=='yes' || value=='true' || value=='1');
415
+ }
416
+ return result;
417
+ }
418
+ TCMP.getFixedHeaders=function(value) {
419
+ //if we can't find it with selectors, the loop through every element
420
+ //in <body> - stopping once we find a position:fixed element and return that.
421
+ var $headers=[];
422
+ var $this;
423
+ jQuery('html div').each(function() {
424
+ $this=jQuery(this);
425
+ if($this.css('position')=='fixed') {
426
+ $headers.push($this);
427
+ }
428
+ });
429
+ /*if(jQuery('#blackbox-web-debug').length>0) {
430
+ $this=jQuery('#blackbox-web-debug');
431
+ $headers.push($this);
432
+ }*/
433
+ return $headers;
434
+ }
435
+ TCMP.parseInt=function(value, defaultValue) {
436
+ defaultValue=(defaultValue || 0);
437
+ value=parseInt(value);
438
+ if(isNaN(value)) {
439
+ value=defaultValue;
440
+ }
441
+ return value;
442
+ }
443
+ TCMP.replace=function(target, search, replacement) {
444
+ //return target.replace(new RegExp(search, 'g'), replacement);
445
+ return target.split(search).join(replacement);
446
+ }
assets/js/plugin.js ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //IntellyWP
2
+ jQuery('.wrap .updated.fade').remove();
3
+ jQuery('.woocommerce-message').remove();
4
+ jQuery('.error').remove();
5
+ jQuery('.info').remove();
6
+ jQuery('.update-nag').remove();
7
+
8
+ jQuery(function() {
9
+ "use strict";
10
+ //WooCommerce errors
11
+ var removeWooUpdateTheme = setInterval(function () {
12
+ if (jQuery('.wrap .updated.fade').length > 0) {
13
+ jQuery('.wrap .updated.fade').remove();
14
+ clearInterval(removeWooUpdateTheme);
15
+ }
16
+ }, 100);
17
+ var removeWooMessage = setInterval(function () {
18
+ if (jQuery('.woocommerce-message').length > 0) {
19
+ jQuery('.woocommerce-message').remove();
20
+ clearInterval(removeWooMessage);
21
+ }
22
+ }, 100);
23
+
24
+ jQuery('.wrap .updated.fade').remove();
25
+ jQuery('.woocommerce-message').remove();
26
+ jQuery('.error').remove();
27
+ jQuery('.info').remove();
28
+ jQuery('.update-nag').remove();
29
+ });
30
+
31
+ jQuery(function() {
32
+ if(jQuery('.wrap .updated.fade').length>0) {
33
+ jQuery('.wrap .updated.fade').remove();
34
+ }
35
+ if(jQuery('.woocommerce-message').length>0) {
36
+ jQuery('.woocommerce-message').remove();
37
+ }
38
+ jQuery('.update-nag,.updated,.error').each(function() {
39
+ var $self=jQuery(this);
40
+ if(!$self.hasClass('iwp')) {
41
+ $self.remove();
42
+ }
43
+ });
44
+ });
45
+
46
+ jQuery(function() {
47
+ "use strict";
48
+
49
+ //WooCommerce errors
50
+ var removeWooUpdateTheme=setInterval(function () {
51
+ if (jQuery('.wrap .updated.fade').length > 0) {
52
+ jQuery('.wrap .updated.fade').remove();
53
+ clearInterval(removeWooUpdateTheme);
54
+ }
55
+ }, 100);
56
+ var removeWooMessage=setInterval(function () {
57
+ if (jQuery('.woocommerce-message').length > 0) {
58
+ jQuery('.woocommerce-message').remove();
59
+ clearInterval(removeWooMessage);
60
+ }
61
+ }, 100);
62
+ });
63
+
64
+ jQuery(function() {
65
+ jQuery('.tcmp-select-onfocus').click(function() {
66
+ var $self=jQuery(this);
67
+ $self.select();
68
+ });
69
+
70
+ jQuery(".tcmp-hideShow").click(function() {
71
+ tcmp_hideShow(this);
72
+ });
73
+ jQuery(".tcmp-hideShow").each(function() {
74
+ tcmp_hideShow(this);
75
+ });
76
+
77
+ function tcmp_hideShow(v) {
78
+ var $source=jQuery(v);
79
+ if($source.attr('tcmp-hideIfTrue') && $source.attr('tcmp-hideShow')) {
80
+ var $destination=jQuery('[name='+$source.attr('tcmp-hideShow')+']');
81
+ if($destination.length==0) {
82
+ $destination=jQuery('#'+$source.attr('tcmp-hideShow'));
83
+ }
84
+ if($destination.length>0) {
85
+ var isChecked=$source.is(":checked");
86
+ var hideIfTrue=($source.attr('tcmp-hideIfTrue').toLowerCase()=='true');
87
+
88
+ if(isChecked) {
89
+ if(hideIfTrue) {
90
+ $destination.hide();
91
+ } else {
92
+ $destination.show();
93
+ }
94
+ } else {
95
+ if(hideIfTrue) {
96
+ $destination.show();
97
+ } else {
98
+ $destination.hide();
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ });
assets/js/tcm-autocomplete.js DELETED
@@ -1,49 +0,0 @@
1
- jQuery(function() {
2
- var url = TCMAutocomplete.url + "?action=tcm_search";
3
- /*
4
- jQuery("[name=optionPosts]").autocomplete({
5
- source: url
6
- , delay: 200
7
- , minLength: 3
8
- });
9
- */
10
-
11
- //var options={multiple:true, multipleSep: ","};
12
- //jQuery("[name=optionPosts]").suggest(url, options);
13
-
14
- jQuery(".tcm-hideShow").click(function() {
15
- tcm_hideShow(this);
16
- });
17
- jQuery(".tcm-hideShow").each(function() {
18
- tcm_hideShow(this);
19
- });
20
-
21
- //mostra o nasconde un div collegato ad una checkbox
22
- function tcm_hideShow(v) {
23
- var $source=jQuery(v);
24
- if($source.attr('tcm-hideIfTrue') && $source.attr('tcm-hideShow')) {
25
- var $destination=jQuery('[name='+$source.attr('tcm-hideShow')+']');
26
- if($destination.length==0) {
27
- $destination=jQuery('#'+$source.attr('tcm-hideShow'));
28
- }
29
- if($destination.length>0) {
30
- var isChecked=$source.is(":checked");
31
- var hideIfTrue=($source.attr('tcm-hideIfTrue').toLowerCase()=='true');
32
-
33
- if(isChecked) {
34
- if(hideIfTrue) {
35
- $destination.hide();
36
- } else {
37
- $destination.show();
38
- }
39
- } else {
40
- if(hideIfTrue) {
41
- $destination.show();
42
- } else {
43
- $destination.hide();
44
- }
45
- }
46
- }
47
- }
48
- }
49
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/landing/edd.png ADDED
Binary file
assets/landing/mockup.png ADDED
Binary file
assets/landing/screenshot-latest.png ADDED
Binary file
assets/landing/tcmp-fb.png ADDED
Binary file
assets/landing/woocommerce.png ADDED
Binary file
assets/landing/wp-ecommerce.png ADDED
Binary file
autoload.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ spl_autoload_register('tcmp_autoload');
3
+ function tcmp_autoload($class) {
4
+ $root=dirname(__FILE__).'/includes/classes/';
5
+ tcmp_autoload_root($root, $class);
6
+ }
7
+ function tcmp_autoload_root($root, $class) {
8
+ $slash=substr($root, strlen($root)-1);
9
+ if($slash!='/' && $slash!='\\') {
10
+ $root.='/';
11
+ }
12
+ $name=str_replace(TCMP_PLUGIN_PREFIX, '', $class);
13
+ if(strpos($class, TCMP_PLUGIN_PREFIX)===FALSE) {
14
+ //autoload only plugin classes
15
+ return;
16
+ }
17
+
18
+ $h=opendir($root);
19
+ while($file=readdir($h)) {
20
+ if(is_dir($root.$file) && $file != '.' && $file != '..') {
21
+ tcmp_autoload_root($root.$file, $class);
22
+ } elseif(file_exists($root.$name.'.php')) {
23
+ include_once($root.$name.'.php');
24
+ } elseif(file_exists($root.$class.'.php')) {
25
+ include_once($root.$class.'.php');
26
+ }
27
+ }
28
+ }
29
+ function tcmp_include_php($root) {
30
+ $h=opendir($root);
31
+ $slash=substr($root, strlen($root)-1);
32
+ if($slash!='/' && $slash!='\\') {
33
+ $root.='/';
34
+ }
35
+
36
+ while($file=readdir($h)) {
37
+ if(is_dir($root.$file) && $file != '.' && $file != '..'){
38
+ tcmp_include_php($root.$file);
39
+ } elseif(strlen($file)>5) {
40
+ $ext='.php';
41
+ $length=strlen($ext);
42
+ $start=$length*-1; //negative
43
+ if(strcasecmp(substr($file, $start), $ext)==0) {
44
+ include_once($root.$file);
45
+ }
46
+ }
47
+ }
48
+ }
includes/actions.php CHANGED
@@ -1,69 +1,3 @@
1
- <?php
2
- /**
3
- * Front-end Actions
4
- *
5
- * @package EDD
6
- * @subpackage Functions
7
- * @copyright Copyright (c) 2015, Pippin Williamson
8
- * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9
- * @since 1.0.8.1
10
- */
11
-
12
- // Exit if accessed directly
13
- if ( ! defined( 'ABSPATH' ) ) exit;
14
-
15
- /**
16
- * Hooks EDD actions, when present in the $_GET superglobal. Every edd_action
17
- * present in $_GET is called using WordPress's do_action function. These
18
- * functions are called on init.
19
- *
20
- * @since 1.0
21
- * @return void
22
- */
23
- add_action('init', 'tcm_do_action');
24
- function tcm_do_action() {
25
- global $tcm;
26
-
27
- if ($tcm->Utils->qs('tcm_action')) {
28
- $args=array_merge($_GET, $_POST, $_COOKIE, $_SERVER);
29
- $name='tcm_'.$tcm->Utils->qs('tcm_action');
30
- if(has_action($name)) {
31
- $tcm->Logger->debug('EXECUTING ACTION=%s', $name);
32
- do_action($name, $args);
33
- } elseif(function_exists($name)) {
34
- $tcm->Logger->debug('EXECUTING FUNCTION=%s DATA=%s', $name, $args);
35
- call_user_func($name, $args);
36
- } elseif(strpos($tcm->Utils->qs('tcm_action'), '_')!==FALSE) {
37
- $pos=strpos($tcm->Utils->qs('tcm_action'), '_');
38
- $what=substr($tcm->Utils->qs('tcm_action'), 0, $pos);
39
- $function=substr($tcm->Utils->qs('tcm_action'), $pos+1);
40
-
41
- $class=NULL;
42
- switch (strtolower($what)) {
43
- case 'manager':
44
- $class=$tcm->Manager;
45
- break;
46
- case 'cron':
47
- $class=$tcm->Cron;
48
- break;
49
- case 'tracking':
50
- $class=$tcm->Tracking;
51
- break;
52
- case 'properties':
53
- $class=$tcm->Options;
54
- break;
55
- }
56
-
57
- if(!$class) {
58
- $tcm->Logger->fatal('NO CLASS FOR=%s IN ACTION=%s', $what, $tcm->Utils->qs('tcm_action'));
59
- } elseif(!method_exists ($class, $function)) {
60
- $tcm->Logger->fatal('NO METHOD FOR=%s IN CLASS=%s IN ACTION=%s', $function, $what, $tcm->Utils->qs('tcm_action'));
61
- } else {
62
- $tcm->Logger->debug('METHOD=%s OF CLASS=%s', $function, $what);
63
- call_user_func(array($class, $function), $args);
64
- }
65
- } else {
66
- $tcm->Logger->fatal('NO FUNCTION FOR==%s', $tcm->Utils->qs('tcm_action'));
67
- }
68
- }
69
- }
1
+ <?php
2
+ // Exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) ) exit;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/admin/about.php DELETED
@@ -1,30 +0,0 @@
1
- <?php
2
- function tcm_ui_about() {
3
- global $tcm;
4
-
5
- $tcm->Options->pushSuccessMessage($tcm->Lang->L('AboutNotice'));
6
- $tcm->Options->writeMessages();
7
-
8
- ?>
9
- <div><?php $tcm->Lang->P('AboutText')?></div>
10
- <style>
11
- ul li {
12
- padding:2px;
13
- }
14
- </style>
15
- <ul>
16
- <li>
17
- <img style="float:left; margin-right:10px;" src="<?php echo TCM_PLUGIN_IMAGES?>email.png" />
18
- <a href="mailto:aleste@intellywp.com">aleste@intellywp.com</a>
19
- </li>
20
- <li>
21
- <img style="float:left; margin-right:10px;" src="<?php echo TCM_PLUGIN_IMAGES?>twitter.png" />
22
- <?php $tcm->Utils->twitter('intellywp')?>
23
- </li>
24
- <li>
25
- <img style="float:left; margin-right:10px;" src="<?php echo TCM_PLUGIN_IMAGES?>internet.png" />
26
- <a href="http://www.intellywp.com" target="_new">IntellyWP.com</a>
27
- </li>
28
- </ul>
29
- <?php
30
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/admin/editor.php CHANGED
@@ -1,117 +1,235 @@
1
  <?php
2
- function tcm_ui_editor() {
3
- global $tcm;
4
-
5
- $tcm->Form->prefix = 'Editor';
6
- $id = intval($tcm->Utils->qs('id', 0));
7
- $action = $tcm->Utils->qs('action');
8
- $snippet = $tcm->Manager->get($id, TRUE);
9
- //var_dump($snippet);
10
-
11
- if (wp_verify_nonce($tcm->Utils->qs('tcm_nonce'), 'tcm_nonce')) {
12
- //var_dump($_POST);
13
- //var_dump($_GET);
14
- foreach ($snippet as $k => $v) {
15
- $snippet[$k] = $tcm->Utils->qs($k);
16
- if (is_string($snippet[$k])) {
17
- $snippet[$k] = stripslashes($snippet[$k]);
18
- }
19
  }
 
 
 
 
20
 
21
- if ($snippet['name'] == '') {
22
- $tcm->Options->pushErrorMessage('Please enter a unique name');
 
 
 
 
23
  } else {
24
- $exist=$tcm->Manager->exists($snippet['name']);
25
- if ($exist && $exist['id'] != $snippet['id']) {
26
- //nonostante il tutto il nome deve essee univoco
27
- $tcm->Options->pushErrorMessage('You have entered a name that already exists. IDs are NOT case-sensitive');
28
- }
 
 
 
 
 
 
 
29
  }
30
- if ($snippet['code'] == '') {
31
- $tcm->Options->pushErrorMessage('Paste your HTML Tracking Code into the textarea');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  }
 
 
 
 
33
 
34
- if (!$tcm->Options->hasErrorMessages()) {
35
- $snippet = $tcm->Manager->put($snippet['id'], $snippet);
36
- if ($id <= 0) {
37
- $tcm->Options->pushSuccessMessage('Editor.Add', $snippet['id'], $snippet['name']);
38
- $snippet = $tcm->Manager->get('', TRUE);
39
- } else {
40
- $tcm->Utils->redirect(TCM_PAGE_MANAGER.'&id='.$id);
41
- exit();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  }
43
  }
44
  }
45
- $tcm->Options->writeMessages();
 
 
46
 
47
- if($tcm->Manager->rc()<=0 && $id<=0) {
48
- $tcm->Utils->redirect(TCM_PAGE_MANAGER);
49
- exit();
 
50
  }
51
- tcm_ui_free_notice();
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  ?>
54
  <script>
55
  jQuery(function(){
56
- var tcmPostTypes=[];
57
-
58
- <?php
59
- $types=$tcm->Utils->query(TCM_QUERY_POST_TYPES);
60
- foreach($types as $v) { ?>
61
- tcmPostTypes.push('<?php echo $v['name']?>');
62
- <?php } ?>
63
-
64
  //enable/disable some part of except creating coherence
65
  function tcmCheckVisible() {
66
- var showExceptCategories=true;
67
- var showExceptTags=true;
68
- var showExceptPostTypes={};
69
- jQuery.each(tcmPostTypes, function (i,v) {
70
- showExceptPostTypes[v]=true;
71
- });
72
-
73
- var $all=jQuery('#includeEverywhereActive');
74
- if(!$all.is(':checked')) {
75
- showExceptCategories=false;
76
- showExceptTags=false;
77
-
78
- jQuery.each(tcmPostTypes, function (i,v) {
79
- isCheck=jQuery('#includePostsOfType_'+v+'_Active').is(':checked');
80
- selection=jQuery('#includePostsOfType_'+v).select2("val");
81
- found=false;
82
- for(i=0; i<selection.length; i++) {
83
- if(parseInt(selection[i])==-1){
84
- found=true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  }
86
- }
87
 
88
- showExceptPostTypes[v]=false;
89
- if(isCheck && found) {
90
- showExceptPostTypes[v]=true;
91
- if(v!='page') {
92
- showExceptCategories=true;
93
- showExceptTags=true;
 
 
 
 
 
 
 
 
 
94
  }
95
  }
96
  });
97
  }
98
 
99
- //hide/show except post type if all the website is selected
100
- //or [All] is selected in a specific post type select
101
- var showExcept=false;
102
- jQuery.each(showExceptPostTypes, function (k,v) {
103
- if(v) {
104
- //at least one post type to show except
105
  showExcept=true;
 
 
106
  }
107
- tcmShowHide('#exceptPostsOfType_'+k+'Box', v);
108
- });
109
-
110
- tcmShowHide('#exceptCategoriesBox', showExceptCategories);
111
- tcmShowHide('#exceptTagsBox', showExceptTags);
112
-
113
- showExcept=(showExcept || showExceptTags || showExceptCategories);
114
- tcmShowHide('#tcm-except-div', showExcept);
115
  }
116
  function tcmShowHide(selector, show) {
117
  $selector=jQuery(selector);
@@ -128,16 +246,16 @@ function tcm_ui_editor() {
128
  }).on('change', function() {
129
  tcmCheckVisible();
130
  });*/
131
- jQuery(".tcmLineTags").select2({
132
  placeholder: "Type here..."
133
  , theme: "classic"
134
  , width: '550px'
135
  });
136
 
137
- jQuery('.tcm-hideShow').click(function() {
138
  tcmCheckVisible();
139
  });
140
- jQuery('.tcm-hideShow, input[type=checkbox]').change(function() {
141
  tcmCheckVisible();
142
  });
143
  jQuery('.tcmLineTags').on('change', function() {
@@ -148,100 +266,149 @@ function tcm_ui_editor() {
148
  </script>
149
  <?php
150
 
151
- $tcm->Form->formStarts();
152
- $tcm->Form->hidden('id', $snippet);
153
- $tcm->Form->checkbox('active', $snippet);
154
- $tcm->Form->text('name', $snippet);
155
- $tcm->Form->textarea('code', $snippet);
156
- $values = array(TCM_POSITION_HEAD, TCM_POSITION_BODY, TCM_POSITION_FOOTER);
157
- $tcm->Form->select('position', $snippet, $values, FALSE);
158
-
159
- $tcm->Form->p('When do you want to add this code?');
160
- $args=array('class'=>'tcm-hideShow tcm-checkbox'
161
- , 'tcm-hideIfTrue'=>'true'
162
- , 'tcm-hideShow'=>'tcm-include-div');
163
- $tcm->Form->checkbox('includeEverywhereActive', $snippet, 1, $args);
164
-
165
- $args=array('id'=>'tcm-include-div', 'name'=>'tcm-include-div', 'style'=>'margin-top:10px;');
166
- $tcm->Form->divStarts($args);
167
- tcm_formOptions('include', $snippet);
168
- $tcm->Form->divEnds();
169
-
170
- $args=array('id'=>'tcm-except-div', 'name'=>'tcm-except-div');
171
- $tcm->Form->divStarts($args);
172
- $tcm->Form->p('Exclude when?');
173
- tcm_formOptions('except', $snippet);
174
- $tcm->Form->divEnds();
175
-
176
- $tcm->Form->nonce('tcm_nonce', 'tcm_nonce');
177
- tcm_notice_pro_features();
178
- $tcm->Form->submit('Save');
179
- if($id>0) {
180
- $tcm->Form->delete($id);
181
- }
182
- $tcm->Form->formEnds();
183
- }
184
 
185
- function tcm_notice_pro_features() {
186
- global $tcm;
 
187
 
188
- ?>
189
- <br/>
190
- <div class="message updated below-h2">
191
- <div style="height:10px;"></div>
192
- <?php
193
- $i=1;
194
- while($tcm->Lang->H('Notice.ProHeader'.$i)) {
195
- $tcm->Lang->P('Notice.ProHeader'.$i);
196
- echo '<br/>';
197
- ++$i;
 
 
 
 
 
 
 
198
  }
199
- $i=1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  ?>
201
- <br/>
202
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
 
204
- $options = array('public' => TRUE, '_builtin' => FALSE);
205
- $q=get_post_types($options, 'names');
206
- if(is_array($q) && count($q)>0) {
207
- sort($q);
208
- $q=implode(', ', $q);
209
- $q='(<b>'.$q.'</b>)';
210
- } else {
211
- $q='';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  }
 
 
213
 
214
- while($tcm->Lang->H('Notice.ProFeature'.$i)) { ?>
215
- <div style="clear:both; margin-top: 2px;"></div>
216
- <div style="float:left; vertical-align:middle; height:24px; margin-right:5px;">
217
- <img src="<?php echo TCM_PLUGIN_IMAGES?>tick.png" />
218
- </div>
219
- <div style="float:left; vertical-align:middle; height:24px;">
220
- <?php $tcm->Lang->P('Notice.ProFeature'.$i, $q)?>
221
- </div>
222
- <?php ++$i;
 
 
 
 
223
  }
224
- ?>
225
- <div style="clear:both;"></div>
226
- <div style="height:10px;"></div>
227
- </div>
228
- <br/>
229
- <?php }
 
 
 
 
 
 
 
 
 
 
 
230
 
231
- function tcm_formOptions($prefix, $snippet) {
232
- global $tcm;
233
 
234
- $types=$tcm->Utils->query(TCM_QUERY_POST_TYPES);
235
  foreach($types as $v) {
236
- $args = array('post_type' => $v['name'], 'all' => TRUE);
237
- $values = $tcm->Utils->query(TCM_QUERY_POSTS_OF_TYPE, $args);
 
238
 
239
- $keyActive=$prefix.'PostsOfType_'.$v['name'].'_Active';
240
- $keyArray=$prefix.'PostsOfType_'.$v['name'];
241
- if($snippet[$keyActive]==0 && count($snippet[$keyArray])==0) {
242
  //when enabled default selected -1
243
  $snippet[$keyArray]=array(-1);
244
  }
245
- $tcm->Form->checkSelect($keyActive, $keyArray, $snippet, $values);
246
  }
247
  }
1
  <?php
2
+ function tcmp_notice_pro_features() {
3
+ global $tcmp;
4
+ ?>
5
+ <br/>
6
+ <div class="message updated below-h2 iwp">
7
+ <div style="height:10px;"></div>
8
+ <?php
9
+ $i=1;
10
+ while($tcmp->Lang->H('Notice.ProHeader'.$i)) {
11
+ $tcmp->Lang->P('Notice.ProHeader'.$i);
12
+ echo '<br/>';
13
+ ++$i;
 
 
 
 
 
14
  }
15
+ $i=1;
16
+ ?>
17
+ <br/>
18
+ <?php
19
 
20
+ /*$options = array('public' => TRUE, '_builtin' => FALSE);
21
+ $q=get_post_types($options, 'names');
22
+ if(is_array($q) && count($q)>0) {
23
+ sort($q);
24
+ $q=implode(', ', $q);
25
+ $q='(<b>'.$q.'</b>)';
26
  } else {
27
+ $q='';
28
+ }*/
29
+ $q='';
30
+ while($tcmp->Lang->H('Notice.ProFeature'.$i)) { ?>
31
+ <div style="clear:both; margin-top: 2px;"></div>
32
+ <div style="float:left; vertical-align:middle; height:24px; margin-right:5px; margin-top:-5px;">
33
+ <img src="<?php echo TCMP_PLUGIN_IMAGES_URI?>tick.png" />
34
+ </div>
35
+ <div style="float:left; vertical-align:middle; height:24px;">
36
+ <?php $tcmp->Lang->P('Notice.ProFeature'.$i, $q)?>
37
+ </div>
38
+ <?php ++$i;
39
  }
40
+ ?>
41
+ <div style="clear:both;"></div>
42
+ <div style="height:10px;"></div>
43
+ <div style="float:right;">
44
+ <?php
45
+ $url=TCMP_PAGE_PREMIUM.'?utm_source=free-users&utm_medium=wp-cta&utm_campaign=wp-plugin';
46
+ ?>
47
+ <a href="<?php echo $url?>" target="_blank">
48
+ <b><?php $tcmp->Lang->P('Notice.ProCTA')?></b>
49
+ </a>
50
+ </div>
51
+ <div style="height:10px; clear:both;"></div>
52
+ </div>
53
+ <br/>
54
+ <?php }
55
+ function tcmp_ui_editor_check($snippet) {
56
+ global $tcmp;
57
+
58
+ $snippet['trackMode']=intval($snippet['trackMode']);
59
+ $snippet['trackPage']=intval($snippet['trackPage']);
60
+
61
+ $snippet['includeEverywhereActive']=0;
62
+ if($snippet['trackPage']==TCMP_TRACK_PAGE_ALL) {
63
+ $snippet['includeEverywhereActive']=1;
64
+ }
65
+ $snippet=$tcmp->Manager->sanitize($snippet['id'], $snippet);
66
+
67
+ if ($snippet['name'] == '') {
68
+ $tcmp->Options->pushErrorMessage('Please enter a unique name');
69
+ } else {
70
+ $exist=$tcmp->Manager->exists($snippet['name']);
71
+ if ($exist && $exist['id'] != $snippet['id']) {
72
+ //nonostante il tutto il nome deve essee univoco
73
+ $tcmp->Options->pushErrorMessage('You have entered a name that already exists. IDs are NOT case-sensitive');
74
  }
75
+ }
76
+ if ($snippet['code'] == '') {
77
+ $tcmp->Options->pushErrorMessage('Paste your HTML Tracking Code into the textarea');
78
+ }
79
 
80
+ if($snippet['trackMode']==TCMP_TRACK_MODE_CODE) {
81
+
82
+ $types=$tcmp->Utils->query(TCMP_QUERY_POST_TYPES);
83
+ if($snippet['trackPage']==TCMP_TRACK_PAGE_SPECIFIC) {
84
+ foreach ($types as $v) {
85
+ $includeActiveKey='includePostsOfType_'.$v['id'].'_Active';
86
+ $includeArrayKey='includePostsOfType_'.$v['id'];
87
+ $exceptActiveKey='exceptPostsOfType_'.$v['id'].'_Active';
88
+ $exceptArrayKey='exceptPostsOfType_'.$v['id'];
89
+
90
+ if ($snippet[$includeActiveKey] == 1 && $snippet[$exceptActiveKey] == 1) {
91
+ if (in_array(-1, $snippet[$includeArrayKey]) && in_array(-1, $snippet[$exceptArrayKey])) {
92
+ $tcmp->Options->pushErrorMessage('Error.IncludeExcludeAll', $v['name']);
93
+ }
94
+ }
95
+ if ($snippet[$includeActiveKey] == 1 && count($snippet[$includeArrayKey]) == 0) {
96
+ $tcmp->Options->pushErrorMessage('Error.IncludeSelectAtLeastOne', $v['name']);
97
+ }
98
+ }
99
+
100
+ //second loop to respect the display order
101
+ foreach ($types as $v) {
102
+ $includeActiveKey='includePostsOfType_'.$v['id'].'_Active';
103
+ $includeArrayKey='includePostsOfType_'.$v['id'];
104
+ $exceptActiveKey='exceptPostsOfType_'.$v['id'].'_Active';
105
+ $exceptArrayKey='exceptPostsOfType_'.$v['id'];
106
+
107
+ if ($snippet[$includeActiveKey] == 1 && in_array(-1, $snippet[$includeArrayKey])) {
108
+ if ($snippet[$exceptActiveKey] == 1 && count($snippet[$exceptArrayKey]) == 0) {
109
+ $tcmp->Options->pushErrorMessage('Error.ExcludeSelectAtLeastOne', $v['name']);
110
+ }
111
+ }
112
+ }
113
+ } else {
114
+ foreach($types as $v) {
115
+ $exceptActiveKey='exceptPostsOfType_'.$v['id'].'_Active';
116
+ $exceptArrayKey='exceptPostsOfType_'.$v['id'];
117
+
118
+ if(isset($snippet[$exceptActiveKey])
119
+ && $snippet[$exceptActiveKey]==1
120
+ && count($snippet[$exceptArrayKey])==0) {
121
+ $tcmp->Options->pushErrorMessage('Error.ExcludeSelectAtLeastOne', $v['name']);
122
+ }
123
  }
124
  }
125
  }
126
+ }
127
+ function tcmp_ui_editor() {
128
+ global $tcmp;
129
 
130
+ $tcmp->Form->prefix='Editor';
131
+ $id=TCMP_ISQS('id', 0);
132
+ if($id==0 && $tcmp->Manager->isLimitReached(FALSE)) {
133
+ $tcmp->Utils->redirect(TCMP_TAB_MANAGER_URI);
134
  }
 
135
 
136
+ $snippet=$tcmp->Manager->get($id, TRUE);
137
+ if (wp_verify_nonce(TCMP_QS('tcmp_nonce'), 'tcmp_nonce')) {
138
+ foreach ($snippet as $k=>$v) {
139
+ $snippet[$k]=TCMP_QS($k);
140
+ if (is_string($snippet[$k])) {
141
+ $snippet[$k]=stripslashes($snippet[$k]);
142
+ }
143
+ }
144
+
145
+ tcmp_ui_editor_check($snippet);
146
+ if (!$tcmp->Options->hasErrorMessages()) {
147
+ $snippet=$tcmp->Manager->put($snippet['id'], $snippet);
148
+ /*if ($id <= 0) {
149
+ $tcmp->Options->pushSuccessMessage('Editor.Add', $snippet['id'], $snippet['name']);
150
+ $snippet=$tcmp->Manager->get('', TRUE);
151
+ } else {
152
+ $tcmp->Utils->redirect(TCMP_PAGE_MANAGER.'&id='.$id);
153
+ exit();
154
+ }*/
155
+ $id=$snippet['id'];
156
+ $tcmp->Utils->redirect(TCMP_PAGE_MANAGER.'&id='.$id); }
157
+ }
158
+ $tcmp->Options->writeMessages()
159
  ?>
160
  <script>
161
  jQuery(function(){
 
 
 
 
 
 
 
 
162
  //enable/disable some part of except creating coherence
163
  function tcmCheckVisible() {
164
+ var $mode=jQuery('[name=trackMode]:checked');
165
+ var showTrackCode=false;
166
+ var showTrackConversion=false;
167
+ if($mode.length>0) {
168
+ if(parseInt($mode.val())!=<?php echo TCMP_TRACK_MODE_CODE ?>) {
169
+ showTrackConversion=true;
170
+ jQuery('#position-box').hide();
171
+
172
+ tcmShowHide('.box-track-conversion', false);
173
+ tcmShowHide('#box-track-conversion-'+$mode.val(), true);
174
+ } else {
175
+ showTrackCode=true;
176
+ jQuery('#position-box').show();
177
+ }
178
+ }
179
+ tcmShowHide('#box-track-conversion', showTrackConversion);
180
+ tcmShowHide('#box-track-code', showTrackCode);
181
+
182
+ var $all=jQuery('[name=trackPage]:checked');
183
+ if($all.length>0 && parseInt($all.val())==<?php echo TCMP_TRACK_PAGE_SPECIFIC ?>) {
184
+ showExcept=false;
185
+ jQuery('[type=checkbox]').each(function() {
186
+ var $check=jQuery(this);
187
+ var id=TCMP.attr($check, 'id', '');
188
+ if(TCMP.startsWith(id, 'include')) {
189
+ var $select=id.replace('_Active', '');
190
+ $select=TCMP.jQuery($select);
191
+
192
+ isCheck=$check.is(':checked');
193
+ selection=$select.select2('val');
194
+ found=false;
195
+ for(i=0; i<selection.length; i++) {
196
+ if(parseInt(selection[i])==-1){
197
+ found=true;
198
+ }
199
  }
 
200
 
201
+ var $except=id.replace('_Active', '');
202
+ $except=$except.replace('Active', '')+'Box';
203
+ $except=$except.substr('include'.length);
204
+ $except='except'+$except;
205
+ $except=jQuery('[id='+$except+']');
206
+
207
+ if(found) {
208
+ showExcept=true;
209
+ if($except.length>0) {
210
+ $except.show();
211
+ }
212
+ } else {
213
+ if($except.length>0) {
214
+ $except.hide();
215
+ }
216
  }
217
  }
218
  });
219
  }
220
 
221
+ showInclude=false;
222
+ if($all.length==0) {
223
+ showExcept=false;
224
+ } else {
225
+ if(parseInt($all.val())==<?php echo TCMP_TRACK_PAGE_ALL ?>) {
 
226
  showExcept=true;
227
+ } else {
228
+ showInclude=true;
229
  }
230
+ }
231
+ tcmShowHide('#tcmp-except-div', showExcept);
232
+ tcmShowHide('#tcmp-include-div', showInclude);
 
 
 
 
 
233
  }
234
  function tcmShowHide(selector, show) {
235
  $selector=jQuery(selector);
246
  }).on('change', function() {
247
  tcmCheckVisible();
248
  });*/
249
+ jQuery('.tcmLineTags,.tcmp-dropdown').select2({
250
  placeholder: "Type here..."
251
  , theme: "classic"
252
  , width: '550px'
253
  });
254
 
255
+ jQuery('.tcmp-hideShow').click(function() {
256
  tcmCheckVisible();
257
  });
258
+ jQuery('.tcmp-hideShow, input[type=checkbox], input[type=radio]').change(function() {
259
  tcmCheckVisible();
260
  });
261
  jQuery('.tcmLineTags').on('change', function() {
266
  </script>
267
  <?php
268
 
269
+ $tcmp->Form->formStarts();
270
+ $tcmp->Form->hidden('id', $snippet);
271
+ $tcmp->Form->hidden('order', $snippet);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
 
273
+ $tcmp->Form->checkbox('active', $snippet);
274
+ $tcmp->Form->text('name', $snippet);
275
+ $tcmp->Form->editor('code', $snippet);
276
 
277
+ $values=array(TCMP_POSITION_HEAD, TCMP_POSITION_BODY, TCMP_POSITION_FOOTER);
278
+ $tcmp->Form->dropdown('position', $snippet, $values, FALSE);
279
+ $values=array(TCMP_DEVICE_TYPE_ALL, TCMP_DEVICE_TYPE_DESKTOP, TCMP_DEVICE_TYPE_MOBILE, TCMP_DEVICE_TYPE_TABLET);
280
+ $tcmp->Form->dropdown('deviceType', $snippet, $values, TRUE);
281
+
282
+ $args=array('id'=>'box-track-mode');
283
+ $tcmp->Form->divStarts($args);
284
+ {
285
+ $tcmp->Form->p('Where do you want to add this code?');
286
+ $tcmp->Form->radio('trackMode', $snippet['trackMode'], TCMP_TRACK_MODE_CODE);
287
+ $plugins=$tcmp->Ecommerce->getActivePlugins();
288
+ if(count($plugins)==0) {
289
+ $plugins=array('Ecommerce'=>array(
290
+ 'name'=>'Ecommerce'
291
+ , 'id'=>TCMP_PLUGINS_NO_PLUGINS
292
+ , 'version'=>'')
293
+ );
294
  }
295
+ $tcmp->Form->tagNew=TRUE;
296
+ foreach($plugins as $k=>$v) {
297
+ $ecommerce=$v['name'];
298
+ if(isset($v['version']) && $v['version']!='') {
299
+ $ecommerce.=' (v.'.$v['version'].')';
300
+ }
301
+ $args=array('label'=>$tcmp->Lang->L('Editor.trackMode_1', $ecommerce));
302
+ $tcmp->Form->radio('trackMode', $snippet['trackMode'], $v['id'], $args);
303
+ }
304
+ $tcmp->Form->tagNew=FALSE;
305
+
306
+ }
307
+ $tcmp->Form->divEnds();
308
+
309
+ $args=array('id'=>'box-track-conversion');
310
+ $tcmp->Form->divStarts($args);
311
+ {
312
+ $tcmp->Form->p('ConversionProductQuestion');
313
  ?>
314
+ <p style="font-style: italic;"><?php $tcmp->Lang->P('Editor.PositionBlocked') ?></p>
315
  <?php
316
+ foreach($plugins as $k=>$v) {
317
+ $args=array('id'=>'box-track-conversion-'.$v['id'], 'class'=>'box-track-conversion');
318
+ $tcmp->Form->divStarts($args);
319
+ {
320
+ if($v['id']==TCMP_PLUGINS_NO_PLUGINS) {
321
+ $plugins=$tcmp->Ecommerce->getPlugins(FALSE);
322
+ $ecommerce='';
323
+ foreach($plugins as $k=>$v) {
324
+ if($ecommerce!='') {
325
+ $ecommerce.=', ';
326
+ }
327
+ $ecommerce.=$k;
328
+ }
329
+ $tcmp->Options->pushErrorMessage('Editor.NoEcommerceFound', $ecommerce);
330
+ $tcmp->Options->writeMessages();
331
+ } else {
332
+ $postType=$tcmp->Ecommerce->getCustomPostType($v['id']);
333
+ $keyActive='CTC_'.$v['id'].'_Active';
334
+ $label=$tcmp->Lang->L('Editor.EcommerceCheck', $v['name'], $v['version']);
335
 
336
+ if($postType!='') {
337
+ $args=array('post_type'=>$postType, 'all'=>TRUE);
338
+ $values=$tcmp->Utils->query(TCMP_QUERY_POSTS_OF_TYPE, $args);
339
+ $keyArray='CTC_'.$v['id'].'_ProductsIds';
340
+ if(count($snippet[$keyArray])==0) {
341
+ //when enabled default selected -1
342
+ $snippet[$keyArray]=array(-1);
343
+ }
344
+
345
+ $args=array('label'=>$label, 'class'=>'tcmp-select tcmLineTags');
346
+ $tcmp->Form->labels=FALSE;
347
+ $tcmp->Form->dropdown($keyArray, $snippet[$keyArray], $values, TRUE, $args);
348
+ $tcmp->Form->labels=TRUE;
349
+ } else {
350
+ $args=array('label'=>$label);
351
+ $tcmp->Form->checkbox($keyActive, $snippet[$keyActive], 1, $args);
352
+ }
353
+ }
354
+ }
355
+ $tcmp->Form->divEnds();
356
+
357
+ $tcmp->Form->br();
358
+ $tcmp->Form->i('ConversionDynamicFields');
359
+ $tcmp->Form->br();
360
+ $tcmp->Form->br();
361
  }
362
+ }
363
+ $tcmp->Form->divEnds();
364
 
365
+ $args=array('id'=>'box-track-code');
366
+ $tcmp->Form->divStarts($args);
367
+ {
368
+ $tcmp->Form->p('In which page do you want to insert this code?');
369
+ $tcmp->Form->radio('trackPage', $snippet['trackPage'], TCMP_TRACK_PAGE_ALL);
370
+ $tcmp->Form->radio('trackPage', $snippet['trackPage'], TCMP_TRACK_PAGE_SPECIFIC);
371
+
372
+ //, 'style'=>'margin-top:10px;'
373
+ $args=array('id'=>'tcmp-include-div');
374
+ $tcmp->Form->divStarts($args);
375
+ {
376
+ $tcmp->Form->p('Include tracking code in which pages?');
377
+ tcmp_formOptions('include', $snippet);
378
  }
379
+ $tcmp->Form->divEnds();
380
+
381
+ $args=array('id'=>'tcmp-except-div');
382
+ $tcmp->Form->divStarts($args);
383
+ {
384
+ $tcmp->Form->p('Do you want to exclude some specific pages?');
385
+ tcmp_formOptions('except', $snippet);
386
+ }
387
+ $tcmp->Form->divEnds();
388
+ }
389
+ $tcmp->Form->divEnds();
390
+
391
+ $tcmp->Form->nonce('tcmp_nonce', 'tcmp_nonce');
392
+ tcmp_notice_pro_features();
393
+ $tcmp->Form->submit('Save');
394
+ $tcmp->Form->formEnds();
395
+ }
396
 
397
+ function tcmp_formOptions($prefix, $snippet) {
398
+ global $tcmp;
399
 
400
+ $types=$tcmp->Utils->query(TCMP_QUERY_POST_TYPES);
401
  foreach($types as $v) {
402
+ $args=array('post_type'=>$v['id'], 'all'=>TRUE);
403
+ $values=$tcmp->Utils->query(TCMP_QUERY_POSTS_OF_TYPE, $args);
404
+ //$tcmp->Form->premium=!in_array($v['name'], array('post', 'page'));
405
 
406
+ $keyActive=$prefix.'PostsOfType_'.$v['id'].'_Active';
407
+ $keyArray=$prefix.'PostsOfType_'.$v['id'];
408
+ if($snippet[$keyActive]==0 && count($snippet[$keyArray])==0 && $prefix!='except') {
409
  //when enabled default selected -1
410
  $snippet[$keyArray]=array(-1);
411
  }
412
+ $tcmp->Form->checkSelect($keyActive, $keyArray, $snippet, $values);
413
  }
414
  }
includes/admin/feedback.php DELETED
@@ -1,45 +0,0 @@
1
- <?php
2
- /**
3
- * Created by PhpStorm.
4
- * User: alessio
5
- * Date: 29/03/2015
6
- * Time: 09:10
7
- */
8
- function tcm_ui_feedback() {
9
- global $tcm;
10
-
11
- $tcm->Form->prefix='Feedback';
12
- if($tcm->Check->nonce('tcm_feedback', 'tcm_feedback')) {
13
- $tcm->Check->email('email');
14
- $tcm->Check->value('body');
15
-
16
- if(!$tcm->Check->hasErrors()) {
17
- $tcm->Options->setFeedbackEmail($tcm->Check->of('email'));
18
- $id=-1;
19
- if($tcm->Check->of('track', 0)) {
20
- $id=$tcm->Tracking->sendTracking(TRUE);
21
- }
22
- $tcm->Check->data['tracking_id']=$id;
23
- $data=$tcm->Utils->remotePost('feedback', $tcm->Check->data);
24
- if($data) {
25
- $tcm->Options->pushSuccessMessage('FeedbackSuccess');
26
- } else {
27
- $tcm->Options->pushErrorMessage('FeedbackError');
28
- }
29
- }
30
- }
31
- ?>
32
- <br>
33
- <h2><?php $tcm->Lang->P('FeedbackHeader')?></h2>
34
- <?php
35
- $tcm->Options->writeMessages();
36
-
37
- $tcm->Form->formStarts();
38
- $tcm->Form->text('email', $tcm->Options->getFeedbackEmail());
39
- $tcm->Form->textarea('body', '', array('rows'=>5));
40
- $tcm->Form->checkbox('track');
41
-
42
- $tcm->Form->nonce('tcm_feedback', 'tcm_feedback');
43
- $tcm->Form->submit('Contact Us');
44
- $tcm->Form->formEnds();
45
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/admin/manager.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  //column renderer
3
- function tcm_ui_manager_column($active, $values=NULL, $hide=FALSE) {
4
- global $tcm;
5
  ?>
6
  <td style="text-align:center;">
7
  <?php
@@ -9,9 +9,9 @@ function tcm_ui_manager_column($active, $values=NULL, $hide=FALSE) {
9
  $text='-';
10
  } else {
11
  if($active) {
12
- $text='<span style="font-weight:bold; color:green">'.$tcm->Lang->L('Yes').'</span>';
13
  } else {
14
- $text='<span style="font-weight:bold; color:red">'.$tcm->Lang->L('No').'</span>';
15
  }
16
  if($active && $values) {
17
  if(!is_array($values)) {
@@ -30,60 +30,46 @@ function tcm_ui_manager_column($active, $values=NULL, $hide=FALSE) {
30
  <?php
31
  }
32
 
33
- function tcm_ui_free_notice() {
34
- global $tcm;
35
 
36
- if($tcm->Manager->rc()<=0) {
37
- $tcm->Options->pushErrorMessage('FreeLicenseReached');
38
- } elseif($tcm->Manager->count()>0) {
39
- $tcm->Options->pushSuccessMessage('PluginLimit.Line1', 6, $tcm->Manager->rc());
40
- $tcm->Options->pushSuccessMessage('PluginLimit.Line2', TCM_PAGE_PREMIUM);
41
- }
42
- $tcm->Options->writeMessages();
43
- }
44
- function tcm_ui_manager() {
45
- global $tcm;
46
-
47
- $id=intval($tcm->Utils->qs('id', 0));
48
- if ($tcm->Utils->is('action', 'delete') && $id>0 && wp_verify_nonce($tcm->Utils->qs('tcm_nonce'), 'tcm_delete')) {
49
- $snippet = $tcm->Manager->get($id);
50
- if ($tcm->Manager->remove($id)) {
51
- $tcm->Options->pushSuccessMessage('CodeDeleteNotice', $id, $snippet['name']);
52
  }
53
- } elseif($id>0) {
54
- $snippet=$tcm->Manager->get($id);
55
- if($tcm->Utils->is('action', 'toggle') && $id>0 && wp_verify_nonce($tcm->Utils->qs('tcm_nonce'), 'tcm_toggle')) {
56
  $snippet['active']=($snippet['active']==0 ? 1 : 0);
57
- $tcm->Manager->put($snippet['id'], $snippet);
58
  }
59
- $tcm->Options->pushSuccessMessage('CodeUpdateNotice', $id, $snippet['name']);
60
  }
61
 
62
- $tcm->Options->writeMessages();
63
- tcm_ui_free_notice();
64
 
65
  //controllo che faccio per essere retrocompatibile con la prima versione
66
  //dove non avevo un id e salvavo tutto con il con il nome quindi una stringa
67
- $snippets=$tcm->Manager->keys();
68
  foreach($snippets as $v) {
69
- $snippet=$tcm->Manager->get($v, FALSE, TRUE);
70
  if(!$snippet) {
71
- $tcm->Manager->remove($v);
72
  } elseif(!is_numeric($v)) {
73
- $tcm->Manager->remove($v);
74
- $tcm->Manager->put('', $snippet);
75
  }
76
  }
77
- $snippets=$tcm->Manager->values();
78
  if (count($snippets)>0) { ?>
79
  <div style="float:left;">
80
- <form method="get" action="" style="margin:5px;" class="alignright">
81
- <input type="hidden" name="page" value="<?php echo TCM_PLUGIN_NAME?>" />
82
- <input type="hidden" name="tab" value="<?php echo TCM_TAB_EDITOR?>" />
83
- <input type="submit" class="button-primary" value="<?php $tcm->Lang->P('Button.Add')?>" />
84
- </form>
85
- <form method="get" style="margin:5px;" class="alignright" action="<?php echo TCM_PAGE_PREMIUM?>">
86
- <input type="submit" class="button" value="<?php $tcm->Lang->P('Button.BuyPRO')?>" />
87
  </form>
88
  </div>
89
  <div style="clear:both;"></div>
@@ -92,23 +78,32 @@ function tcm_ui_manager() {
92
  .widefat th {
93
  font-weight: bold!important;
94
  }
 
 
 
 
 
 
95
  </style>
96
- <table class="widefat fixed" style="width:850px;">
97
  <thead>
98
  <tr>
99
- <th><?php $tcm->Lang->P('Name')?></th>
100
- <th><?php $tcm->Lang->P('Position')?></th>
101
- <th style="text-align:center;"><?php $tcm->Lang->P('Active?')?></th>
102
- <th style="text-align:center;"><?php $tcm->Lang->P('Each pages?')?></th>
103
- <th style="text-align:center;"><?php $tcm->Lang->P('Count')?></th>
104
- <th style="text-align:center;"><?php $tcm->Lang->P('Actions')?></th>
105
  </tr>
106
  </thead>
107
- <tbody>
108
- <?php foreach ($snippets as $snippet) { ?>
109
- <tr>
110
- <td><?php echo $snippet['name']?></td>
111
- <td><?php $tcm->Lang->P('Editor.position.'.$snippet['position'])?></td>
 
 
 
112
  <td style="text-align:center;">
113
  <?php
114
  $color='red';
@@ -119,33 +114,89 @@ function tcm_ui_manager() {
119
  $text='Yes';
120
  $question='QuestionActiveOff';
121
  }
122
- $text='<span style="font-weight:bold; color:'.$color.'">'.$tcm->Lang->L($text).'</span>';
123
  ?>
124
- <a onclick="return confirm('<?php echo $tcm->Lang->L($question)?>');" href="<?php echo TCM_TAB_MANAGER_URI?>&tcm_nonce=<?php echo esc_attr(wp_create_nonce('tcm_toggle')); ?>&action=toggle&id=<?php echo $snippet['id'] ?>">
125
  <?php echo $text?>
126
  </a>
127
  </td>
128
- <?php
129
- $hide=!$snippet['active'];
130
- tcm_ui_manager_column($snippet['includeEverywhereActive'], NULL, $hide);
131
- ?>
132
- <td style="text-align:center;"><?php echo $snippet['codesCount']?></td>
 
 
 
 
 
 
 
 
 
 
133
  <td style="text-align:center;">
134
- <a href="<?php echo TCM_TAB_EDITOR_URI?>&id=<?php echo $snippet['id'] ?>">
135
- <?php echo $tcm->Lang->L('Edit')?>
136
- </a>
137
- &nbsp;|&nbsp;
138
- <span class="trash">
139
- <a onclick="return confirm('<?php echo $tcm->Lang->L('Are you sure you want to delete this code?')?>');" href="<?php echo TCM_TAB_MANAGER_URI?>&tcm_nonce=<?php echo esc_attr(wp_create_nonce('tcm_delete')); ?>&action=delete&id=<?php echo $snippet['id'] ?>">
140
- <?php echo $tcm->Lang->L('Delete')?>
141
- </a>
142
- </span>
143
  </td>
144
  </tr>
145
  <?php } ?>
146
  </tbody>
147
  </table>
148
- <?php } else { ?>
149
- <h2><?php $tcm->Lang->P('EmptyTrackingList', TCM_TAB_EDITOR_URI)?></h2>
150
- <?php } ?>
151
- <?php }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
  //column renderer
3
+ function tcmp_ui_manager_column($active, $values=NULL, $hide=FALSE) {
4
+ global $tcmp;
5
  ?>
6
  <td style="text-align:center;">
7
  <?php
9
  $text='-';
10
  } else {
11
  if($active) {
12
+ $text='<span style="font-weight:bold; color:green">'.$tcmp->Lang->L('Yes').'</span>';
13
  } else {
14
+ $text='<span style="font-weight:bold; color:red">'.$tcmp->Lang->L('No').'</span>';
15
  }
16
  if($active && $values) {
17
  if(!is_array($values)) {
30
  <?php
31
  }
32
 
33
+ function tcmp_ui_manager() {
34
+ global $tcmp;
35
 
36
+ $id=TCMP_ISQS('id', 0);
37
+ if (TCMP_SQS('action')=='delete' && $id>0 && wp_verify_nonce(TCMP_QS('tcmp_nonce'), 'tcmp_delete')) {
38
+ $snippet=$tcmp->Manager->get($id);
39
+ if ($tcmp->Manager->remove($id)) {
40
+ $tcmp->Options->pushSuccessMessage('CodeDeleteNotice', $id, $snippet['name']);
 
 
 
 
 
 
 
 
 
 
 
41
  }
42
+ } else if($id!='') {
43
+ $snippet=$tcmp->Manager->get($id);
44
+ if($tcmp->Utils->is('action', 'toggle') && $id>0 && wp_verify_nonce(TCMP_QS('tcmp_nonce'), 'tcmp_toggle')) {
45
  $snippet['active']=($snippet['active']==0 ? 1 : 0);
46
+ $tcmp->Manager->put($snippet['id'], $snippet);
47
  }
48
+ $tcmp->Options->pushSuccessMessage('CodeUpdateNotice', $id, $snippet['name']);
49
  }
50
 
51
+ $tcmp->Manager->isLimitReached(TRUE);
52
+ $tcmp->Options->writeMessages();
53
 
54
  //controllo che faccio per essere retrocompatibile con la prima versione
55
  //dove non avevo un id e salvavo tutto con il con il nome quindi una stringa
56
+ $snippets=$tcmp->Manager->keys();
57
  foreach($snippets as $v) {
58
+ $snippet=$tcmp->Manager->get($v, FALSE, TRUE);
59
  if(!$snippet) {
60
+ $tcmp->Manager->remove($v);
61
  } elseif(!is_numeric($v)) {
62
+ $tcmp->Manager->remove($v);
63
+ $tcmp->Manager->put('', $snippet);
64
  }
65
  }
66
+ $snippets=$tcmp->Manager->values();
67
  if (count($snippets)>0) { ?>
68
  <div style="float:left;">
69
+ <form method="get" action="" style="margin:5px; float:left;">
70
+ <input type="hidden" name="page" value="<?php echo TCMP_PLUGIN_SLUG?>" />
71
+ <input type="hidden" name="tab" value="<?php echo TCMP_TAB_EDITOR?>" />
72
+ <input type="submit" class="button-primary" value="<?php $tcmp->Lang->P('Button.Add')?>" />
 
 
 
73
  </form>
74
  </div>
75
  <div style="clear:both;"></div>
78
  .widefat th {
79
  font-weight: bold!important;
80
  }
81
+ table input {
82
+ font-size: 13px;
83
+ }
84
+ .widefat thead td, .widefat thead th {
85
+ border-bottom: 0px!important;
86
+ }
87
  </style>
88
+ <table class="widefat fixed" style="width:100%" id="tblSortable">
89
  <thead>
90
  <tr>
91
+ <th style="width:30px;">#N</th>
92
+ <th style="width:50px; text-align:center;"><?php $tcmp->Lang->P('Active?')?></th>
93
+ <th><?php $tcmp->Lang->P('Name')?></th>
94
+ <th><?php $tcmp->Lang->P('Where?')?></th>
95
+ <th style="text-align:center;"><?php $tcmp->Lang->P('Shortcode')?></th>
96
+ <th style="text-align:center;"><?php $tcmp->Lang->P('Actions')?></th>
97
  </tr>
98
  </thead>
99
+ <tbody class="table-body">
100
+ <?php
101
+ $i=1;
102
+ foreach ($snippets as $snippet) {
103
+ $bClass=(($i%2)==1 ? 'odd' : 'even');
104
+ ?>
105
+ <tr class="<?php echo $bClass?>" id="row_<?php echo $snippet['id']?>">
106
+ <td>#<?php echo $i++ ?></td>
107
  <td style="text-align:center;">
108
  <?php
109
  $color='red';
114
  $text='Yes';
115
  $question='QuestionActiveOff';
116
  }
117
+ $text='<span style="font-weight:bold; color:'.$color.'">'.$tcmp->Lang->L($text).'</span>';
118
  ?>
119
+ <a onclick="return confirm('<?php echo $tcmp->Lang->L($question)?>');" href="<?php echo TCMP_TAB_MANAGER_URI?>&tcmp_nonce=<?php echo esc_attr(wp_create_nonce('tcmp_toggle')); ?>&action=toggle&id=<?php echo $snippet['id'] ?>">
120
  <?php echo $text?>
121
  </a>
122
  </td>
123
+ <td><?php echo $snippet['name']?></td>
124
+ <td>
125
+ <?php
126
+ if($tcmp->Manager->isModeScript($snippet)) {
127
+ if($tcmp->Manager->isPageEverywhere($snippet)) {
128
+ $text='Everywhere';
129
+ } else {
130
+ $text='Specific Pages';
131
+ }
132
+ } else {
133
+ $text='Conversion';
134
+ }
135
+ $tcmp->Lang->P($text);
136
+ ?>
137
+ </td>
138
  <td style="text-align:center;">
139
+ <input type="text" style="width:110px; text-align:center;" value='[tcm id="<?php echo esc_html($snippet['id']); ?>"]' readonly="readonly" class="tcmp-select-onfocus" />
140
+ </td>
141
+ <td style="text-align:center;">
142
+ <input type="button" class="button button-secondary" value="<?php $tcmp->Lang->P('Edit')?>" onclick="location.href='<?php echo TCMP_TAB_EDITOR_URI?>&id=<?php echo $snippet['id'] ?>';"/>
143
+ <input type="button" class="button button-secondary" value="<?php $tcmp->Lang->P('Delete?')?>" onclick="TCMP_btnDeleteClick(<?php echo $snippet['id'] ?>)"/>
 
 
 
 
144
  </td>
145
  </tr>
146
  <?php } ?>
147
  </tbody>
148
  </table>
149
+ <script>
150
+ function TCMP_btnDeleteClick(id) {
151
+ var success=confirm('<?php echo $tcmp->Lang->L('Question.DeleteQuestion')?>');
152
+ if(success) {
153
+ var href='<?php echo TCMP_TAB_MANAGER_URI?>&tcmp_nonce=<?php echo esc_attr(wp_create_nonce('tcmp_delete')); ?>&action=delete&id=';
154
+ location.href=href+id;
155
+ }
156
+ }
157
+ </script>
158
+ <?php
159
+ tcmp_notice_pro_features();
160
+ if(count($snippets)>1) {
161
+ tcmp_manager_sortable_scripts();
162
+ }
163
+ } else { ?>
164
+ <h2><?php $tcmp->Lang->P('EmptyTrackingList', TCMP_TAB_EDITOR_URI)?></h2>
165
+ <?php }
166
+ }
167
+ function tcmp_manager_sortable_scripts() {
168
+ ?>
169
+ <style>
170
+ .ui-state-highlight {
171
+ border: 1px dotted red!important;
172
+ background-color: #F4E449!important;
173
+ }
174
+ #tblSortable tbody tr:hover {
175
+ cursor: move!important;
176
+ }
177
+ #tblSortable tbody tr a:hover {
178
+ cursor: hand!important;
179
+ }
180
+ </style>
181
+ <script>
182
+ jQuery(function() {
183
+ var $sortable=jQuery("#tblSortable .table-body");
184
+ $sortable.sortable({
185
+ tolerance:'intersect'
186
+ , cursor:'move'
187
+ , items:'tr'
188
+ , placeholder:'ui-state-highlight'
189
+ , nested: 'tbody'
190
+ , update: function(event, ui) {
191
+ var orders=$sortable.sortable('serialize');
192
+ var data={action: 'TCMP_changeOrder', order: orders};
193
+ jQuery.post(ajaxurl, data, function(result) {
194
+ console.log(result);
195
+ });
196
+ }
197
+ });
198
+ $sortable.disableSelection();
199
+ });
200
+ </script>
201
+ <?php
202
+ }
includes/admin/metabox.php CHANGED
@@ -1,71 +1,78 @@
1
  <?php
2
- function tcm_ui_metabox($post) {
3
- global $tcm;
4
  // Add an nonce field so we can check for it later.
5
- wp_nonce_field('tcm_meta_box', 'tcm_meta_box_nonce');
6
 
7
  $args=array('metabox'=>TRUE, 'field'=>'id');
8
- $ids=$tcm->Manager->getCodes(-1, $post, $args);
9
- $snippets=$tcm->Manager->values();
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  ?>
11
  <div>
12
- <?php $tcm->Lang->P('Select existing Tracking Code')?>
13
  </div>
14
- <input type="hidden" name="tcm_previous_ids" value="<?php echo implode(',', $ids)?>" />
15
 
16
  <div>
17
  <?php
18
- $postType=$post->post_type;
19
  foreach($snippets as $snippet) {
20
  $id=$snippet['id'];
 
 
 
 
21
  $disabled='';
22
  $checked='';
23
 
24
- if($snippet['active']==0) {
25
- $disabled=' DISABLED';
26
- } elseif($snippet['exceptPostsOfType_'.$postType.'_Active']>0 && in_array(-1, $snippet['exceptPostsOfType_'.$postType])) {
27
- //the user have excluded all the posts of this type from code definition
28
  $disabled=' DISABLED';
29
- } else {
30
- if(in_array($id, $ids)) {
31
- $checked=' checked';
32
- $active=($snippet['includePostsOfType_'.$postType.'_Active']>0);
33
- if(!$active) {
34
- $checked='';
35
- }
36
- }
37
  }
38
  ?>
39
- <input type="checkbox" class="tcm-checkbox" name="tcm_ids[]" value="<?php echo $id?>" <?php echo $checked ?> <?php echo $disabled ?> />
40
- <a href="<?php echo TCM_TAB_EDITOR_URI?>&id=<?php echo $id?>" target="_blank"><?php echo $snippet['name']?></a>
 
41
  <br/>
42
  <?php } ?>
43
  </div>
44
 
45
  <br/>
46
- <?php if($tcm->Manager->rc()>0) { ?>
47
- <div>
48
- <label for="tcm_name"><?php $tcm->Lang->P('Or add a name')?></label>
49
- <br/>
50
- <input type="text" name="tcm_name" value="" style="width:100%"/>
51
- </div>
52
- <div>
53
- <label for="code"><?php $tcm->Lang->P('and paste HTML code here')?></label>
54
- <br/>
55
- <textarea dir="ltr" dirname="ltr" name="tcm_code" class="tcm-textarea" style="width:100%; height:175px;"></textarea>
56
- </div>
57
- <?php } else { ?>
58
- <span style="color:red;font-weight:bold;"><?php $tcm->Lang->P('FreeLicenseReached')?></span>
59
- <?php }
60
- }
61
 
62
  //si aggancia per creare i metabox in post e page
63
- add_action('add_meta_boxes', 'tcm_add_meta_box');
64
- function tcm_add_meta_box() {
65
- global $tcm;
66
 
67
  $free=array('post', 'page');
68
- $options=$tcm->Options->getMetaboxPostTypes();
69
  $screens=array();
70
  foreach($options as $k=>$v) {
71
  if(intval($v)>0) {
@@ -75,21 +82,46 @@ function tcm_add_meta_box() {
75
  if(count($screens)>0) {
76
  foreach ($screens as $screen) {
77
  add_meta_box(
78
- 'tcm_sectionid'
79
- , $tcm->Lang->L('Tracking Code by IntellyWP')
80
- , 'tcm_ui_metabox'
81
  , $screen
82
  , 'side'
83
  );
84
  }
85
  }
86
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  //si aggancia a quando un post viene salvato per salvare anche gli altri dati del metabox
88
- add_action('save_post', 'tcm_save_meta_box_data');
89
- function tcm_save_meta_box_data($postId) {
90
- global $tcm;
91
 
92
- $postType=$_POST['post_type'];
93
  //in case of custom post type edit_ does not exist
94
  //if (!current_user_can('edit_'.$postType, $postId)) {
95
  // return;
@@ -99,76 +131,79 @@ function tcm_save_meta_box_data($postId) {
99
  if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
100
  return;
101
  }
102
- if (!isset($_POST['tcm_meta_box_nonce'])) {
103
  return;
104
  }
105
  // Verify that the nonce is valid.
106
- if (!wp_verify_nonce( $_POST['tcm_meta_box_nonce'], 'tcm_meta_box')) {
107
  return;
108
  }
109
 
110
- $previousIds=explode(',', $tcm->Utils->qs('tcm_previous_ids'));
111
- $currentIds=$tcm->Utils->qs('tcm_ids', array());
112
- $keyArray='PostsOfType_'.$postType;
113
- $keyActive=$keyArray.'_Active';
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
- if($previousIds!=$currentIds) {
116
- //first remove by ids from old snippets
117
- foreach($previousIds as $id) {
118
  $id=intval($id);
119
- if($id>0 && !in_array($id, $currentIds)) {
120
- $snippet=$tcm->Manager->get($id);
121
- if($snippet!=NULL) {
122
- //remove my id from post type includes
123
- $snippet['include'.$keyArray] = array_diff($snippet['include'.$keyArray], array($postId));
124
- $snippet['include'.$keyArray] = array_unique($snippet['include'.$keyArray]);
125
- $snippet['include'.$keyActive]=(count($snippet['include'.$keyArray])>0 ? 1 : 0);
126
-
127
- //include it in post type exception
128
- if($snippet['except'.$keyActive]==0) {
129
- $snippet['except'.$keyArray]=array();
130
- }
131
- $snippet['except'.$keyArray] = array_merge($snippet['except'.$keyArray], array($postId));
132
- $snippet['except'.$keyArray] = array_unique($snippet['except'.$keyArray]);
133
- $snippet['except'.$keyActive]=1;
134
- }
135
- $tcm->Manager->put($id, $snippet);
136
  }
137
- }
138
- //after insert by id in the snippets selected
139
- foreach($currentIds as $id) {
140
- $id=intval($id);
141
- if($id>0 && !in_array($id, $previousIds)) {
142
- $snippet = $tcm->Manager->get($id);
143
- if ($snippet) {
144
- //include my id in post type includes
145
- if($snippet['include'.$keyActive]==0) {
146
- $snippet['include'.$keyArray]=array();
147
- }
148
- $snippet['include'.$keyArray] = array_merge($snippet['include'.$keyArray], array($postId));
149
- $snippet['include'.$keyArray] = array_unique($snippet['include'.$keyArray]);
150
- $snippet['include'.$keyActive]=1;
151
- //remove it from post type exception
152
- $snippet['except'.$keyArray] = array_diff($snippet['except'.$keyArray], array($postId));
153
- $snippet['except'.$keyArray] = array_unique($snippet['except'.$keyArray]);
154
- $snippet['except'.$keyActive]=(count($snippet['except'.$keyArray])>0 ? 1 : 0);
155
- }
156
- $tcm->Manager->put($id, $snippet);
157
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  }
159
  }
160
 
161
- $name=stripslashes($tcm->Utils->qs('tcm_name'));
162
- $code=$tcm->Utils->qs('tcm_code');
163
- if($name!='' && $code!='' && !$tcm->Manager->exists($name) && $tcm->Manager->rc()>0) {
 
 
 
 
164
  $snippet=array(
165
  'active'=>1
166
  , 'name'=>$name
167
  , 'code'=>$code
 
 
168
  );
169
  $snippet['include'.$keyActive]=1;
170
  $snippet['include'.$keyArray]=array($postId);
171
- $snippet=$tcm->Manager->put('', $snippet);
172
- $tcm->Logger->debug("NEW SNIPPET REGISTRED=%s", $snippet);
173
  }
174
  }
1
  <?php
2
+ function tcmp_ui_metabox($post) {
3
+ global $tcmp;
4
  // Add an nonce field so we can check for it later.
5
+ wp_nonce_field('tcmp_meta_box', 'tcmp_meta_box_nonce');
6
 
7
  $args=array('metabox'=>TRUE, 'field'=>'id');
8
+ $ids=$tcmp->Manager->getCodes(-1, $post, $args);
9
+
10
+ $allIds=array();
11
+ $snippets=$tcmp->Manager->values();
12
+ $postType=$post->post_type;
13
+ foreach($snippets as $snippet) {
14
+ if($snippet['trackMode']==TCMP_TRACK_MODE_CODE) {
15
+ if($snippet['active']!=0) {
16
+ if($snippet['exceptPostsOfType_'.$postType.'_Active']==0
17
+ || !in_array(-1, $snippet['exceptPostsOfType_'.$postType])) {
18
+ $allIds[]=$snippet['id'];
19
+ }
20
+ }
21
+ }
22
+ }
23
  ?>
24
  <div>
25
+ <?php $tcmp->Lang->P('Select existing Tracking Code')?>..
26
  </div>
27
+ <input type="hidden" name="tcmp_all_ids" value="<?php echo implode(',', $allIds)?>" />
28
 
29
  <div>
30
  <?php
 
31
  foreach($snippets as $snippet) {
32
  $id=$snippet['id'];
33
+ if($snippet['trackMode']!=TCMP_TRACK_MODE_CODE) {
34
+ continue;
35
+ }
36
+
37
  $disabled='';
38
  $checked='';
39
 
40
+ if(!in_array($id, $allIds)) {
 
 
 
41
  $disabled=' DISABLED';
42
+ } elseif(in_array($id, $ids)) {
43
+ $checked=' CHECKED';
 
 
 
 
 
 
44
  }
45
  ?>
46
+ <input type="checkbox" class="tcmp-checkbox" name="tcmp_ids[]" value="<?php echo $id?>" <?php echo $checked ?> <?php echo $disabled ?> />
47
+ <?php echo $snippet['name']?>
48
+ <a href="<?php echo TCMP_TAB_EDITOR_URI?>&id=<?php echo $id?>" target="_blank">&nbsp;››</a>
49
  <br/>
50
  <?php } ?>
51
  </div>
52
 
53
  <br/>
54
+ <div>
55
+ <label for="tcmp_name"><?php $tcmp->Lang->P('Or add a name')?></label>
56
+ <br/>
57
+ <input type="text" name="tcmp_name" value="" style="width:100%"/>
58
+ </div>
59
+ <div>
60
+ <label for="code"><?php $tcmp->Lang->P('and paste HTML code here')?></label>
61
+ <br/>
62
+ <textarea dir="ltr" dirname="ltr" name="tcmp_code" class="tcmp-textarea" style="width:100%; height:175px;"></textarea>
63
+ </div>
64
+
65
+ <div style="clear:both"></div>
66
+ <i>Saving the post you'll save the tracking code</i>
67
+ <?php }
 
68
 
69
  //si aggancia per creare i metabox in post e page
70
+ add_action('add_meta_boxes', 'tcmp_add_meta_box');
71
+ function tcmp_add_meta_box() {
72
+ global $tcmp;
73
 
74
  $free=array('post', 'page');
75
+ $options=$tcmp->Options->getMetaboxPostTypes();
76
  $screens=array();
77
  foreach($options as $k=>$v) {
78
  if(intval($v)>0) {
82
  if(count($screens)>0) {
83
  foreach ($screens as $screen) {
84
  add_meta_box(
85
+ 'tcmp_sectionid'
86
+ , $tcmp->Lang->L('Tracking Code PRO by IntellyWP')
87
+ , 'tcmp_ui_metabox'
88
  , $screen
89
  , 'side'
90
  );
91
  }
92
  }
93
  }
94
+ function tcmp_edit_snippet_array($post, &$snippet, $prefix, $diff) {
95
+ global $tcmp;
96
+ $postId=$tcmp->Utils->get($post, 'ID', FALSE);
97
+ if($postId===FALSE) {
98
+ $postId=$tcmp->Utils->get($post, 'post_ID');
99
+ }
100
+ $postType=$tcmp->Utils->get($post, 'post_type');
101
+
102
+ $keyArray='PostsOfType_'.$postType;
103
+ $keyActive=$keyArray.'_Active';
104
+ if($snippet[$prefix.$keyActive]==0) {
105
+ $snippet[$prefix.$keyArray]=array();
106
+ }
107
+ $k=$prefix.$keyArray;
108
+ if($diff) {
109
+ $snippet[$k]=array_diff($snippet[$k], array($postId));
110
+ } else {
111
+ $snippet[$k]=array_merge($snippet[$k], array($postId));
112
+ if(in_array(-1, $snippet[$k])) {
113
+ $snippet[$k]=array(-1);
114
+ }
115
+ }
116
+ $snippet[$k]=array_unique($snippet[$k]);
117
+ $snippet[$prefix.$keyActive]=(count($snippet[$k])>0 ? 1 : 0);
118
+ return $snippet;
119
+ }
120
  //si aggancia a quando un post viene salvato per salvare anche gli altri dati del metabox
121
+ add_action('save_post', 'tcmp_save_meta_box_data');
122
+ function tcmp_save_meta_box_data($postId) {
123
+ global $tcmp;
124
 
 
125
  //in case of custom post type edit_ does not exist
126
  //if (!current_user_can('edit_'.$postType, $postId)) {
127
  // return;
131
  if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
132
  return;
133
  }
134
+ if (!isset($_POST['tcmp_meta_box_nonce']) || !isset($_POST['post_type'])) {
135
  return;
136
  }
137
  // Verify that the nonce is valid.
138
+ if (!wp_verify_nonce($_POST['tcmp_meta_box_nonce'], 'tcmp_meta_box')) {
139
  return;
140
  }
141
 
142
+ $args=array('metabox'=>TRUE, 'field'=>'id');
143
+ $ids=$tcmp->Manager->getCodes(-1, $_POST, $args);
144
+ if(!is_array($ids)) {
145
+ $ids=array();
146
+ }
147
+
148
+ $allIds=TCMP_QS('tcmp_all_ids');
149
+ if($allIds===FALSE || $allIds=='') {
150
+ $allIds=array();
151
+ } else {
152
+ $allIds=explode(',', $allIds);
153
+ }
154
+ $currentIds=TCMP_ASQS('tcmp_ids', array());
155
+ if(!is_array($currentIds)) {
156
+ $currentIds=array();
157
+ }
158
 
159
+ if($ids!=$currentIds) {
160
+ foreach($allIds as $id) {
 
161
  $id=intval($id);
162
+ if($id<=0) {
163
+ continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  }
165
+ if(in_array($id, $currentIds) && in_array($id, $ids)) {
166
+ //selected now and already selected
167
+ continue;
168
+ }
169
+ if(!in_array($id, $currentIds) && !in_array($id, $ids)) {
170
+ //not selected now and not already selected
171
+ continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  }
173
+
174
+ $snippet=$tcmp->Manager->get($id);
175
+ if($snippet==NULL) {
176
+ continue;
177
+ }
178
+
179
+ $snippet=tcmp_edit_snippet_array($_POST, $snippet, 'include', TRUE);
180
+ $snippet=tcmp_edit_snippet_array($_POST, $snippet, 'except', TRUE);
181
+ if(in_array($id, $currentIds)) {
182
+ $snippet=tcmp_edit_snippet_array($_POST, $snippet, 'include', FALSE);
183
+ } else {
184
+ $snippet=tcmp_edit_snippet_array($_POST, $snippet, 'except', FALSE);
185
+ }
186
+ $tcmp->Manager->put($id, $snippet);
187
  }
188
  }
189
 
190
+ $name=TCMP_SQS('tcmp_name');
191
+ $code=stripslashes(TCMP_QS('tcmp_code'));
192
+ if($name!='' && $code!='') {
193
+ $postType=TCMP_SQS('post_type');
194
+ $keyArray='PostsOfType_'.$postType;
195
+ $keyActive=$keyArray.'_Active';
196
+
197
  $snippet=array(
198
  'active'=>1
199
  , 'name'=>$name
200
  , 'code'=>$code
201
+ , 'trackPage'=>TCMP_TRACK_PAGE_SPECIFIC
202
+ , 'trackMode'=>TCMP_TRACK_MODE_CODE
203
  );
204
  $snippet['include'.$keyActive]=1;
205
  $snippet['include'.$keyArray]=array($postId);
206
+ $snippet=$tcmp->Manager->put('', $snippet);
207
+ $tcmp->Log->debug("NEW SNIPPET REGISTRED=%s", $snippet);
208
  }
209
  }
includes/admin/settings.php CHANGED
@@ -1,44 +1,50 @@
1
  <?php
2
- function tcm_ui_settings() {
3
- global $tcm;
4
 
5
- $track=$tcm->Utils->qs('track', '');
6
  if($track!='') {
7
  $track=intval($track);
8
- $tcm->Options->setTrackingEnable($track);
9
- $tcm->Tracking->sendTracking(TRUE);
10
  }
11
 
12
- $uri=TCM_TAB_SETTINGS_URI.'&track=';
13
- if($tcm->Options->isTrackingEnable()) {
14
  $uri.='0';
15
- $tcm->Options->pushSuccessMessage('EnableAllowTrackingNotice', $uri);
16
  } else {
17
  $uri.='1';
18
- $tcm->Options->pushErrorMessage('DisableAllowTrackingNotice', $uri);
19
  }
20
- $tcm->Options->writeMessages();
 
 
 
21
 
22
- $tcm->Form->prefix='License';
23
- if($tcm->Check->nonce('tcm_settings')) {
24
- $options=$tcm->Options->getMetaboxPostTypes();
25
- foreach($options as $k=>$v) {
26
- $v=intval($tcm->Utils->qs('metabox_'.$k, 0));
27
  $options[$k]=$v;
28
  }
29
- $tcm->Options->setMetaboxPostTypes($options);
30
  }
31
 
32
- $tcm->Form->formStarts();
33
- $tcm->Form->p('MetaboxSection');
34
- $metaboxes=$tcm->Options->getMetaboxPostTypes();
35
 
36
- $types=$tcm->Utils->query(TCM_QUERY_POST_TYPES);
37
- foreach($types as $v) {
38
- $v=$v['name'];
39
- $tcm->Form->checkbox('metabox_'.$v, $metaboxes[$v]);
 
 
40
  }
41
- $tcm->Form->nonce('tcm_settings');
42
- $tcm->Form->submit('Save');
43
- $tcm->Form->formEnds();
 
44
  }
1
  <?php
2
+ function tcmp_ui_track() {
3
+ global $tcmp;
4
 
5
+ $track=TCMP_SQS('track', '');
6
  if($track!='') {
7
  $track=intval($track);
8
+ $tcmp->Options->setTrackingEnable($track);
9
+ $tcmp->Tracking->sendTracking(TRUE);
10
  }
11
 
12
+ $uri=TCMP_TAB_SETTINGS_URI.'&track=';
13
+ if($tcmp->Options->isTrackingEnable()) {
14
  $uri.='0';
15
+ $tcmp->Options->pushSuccessMessage('EnableAllowTrackingNotice', $uri);
16
  } else {
17
  $uri.='1';
18
+ $tcmp->Options->pushErrorMessage('DisableAllowTrackingNotice', $uri);
19
  }
20
+ $tcmp->Options->writeMessages();
21
+ }
22
+ function tcmp_ui_settings() {
23
+ global $tcmp;
24
 
25
+ $tcmp->Form->prefix='License';
26
+ if($tcmp->Check->nonce('tcmp_license')) {
27
+ $options=$tcmp->Options->getMetaboxPostTypes();
28
+ foreach ($options as $k => $v) {
29
+ $v=TCMP_ISQS('metabox_' . $k, 0);
30
  $options[$k]=$v;
31
  }
32
+ $tcmp->Options->setMetaboxPostTypes($options);
33
  }
34
 
35
+ $tcmp->Form->formStarts();
36
+ $tcmp->Form->p('MetaboxSection');
37
+ $metaboxes=$tcmp->Options->getMetaboxPostTypes();
38
 
39
+ $types=$tcmp->Utils->query(TCMP_QUERY_POST_TYPES);
40
+ foreach ($types as $v) {
41
+ $v=$v['id'];
42
+ //$tcmp->Form->tags=TRUE;
43
+ //$tcmp->Form->premium=!in_array($v, array('post', 'page'));
44
+ $tcmp->Form->checkbox('metabox_'.$v, $metaboxes[$v]);
45
  }
46
+ $tcmp->Form->nonce('tcmp_license');
47
+ $tcmp->Form->br();
48
+ $tcmp->Form->submit('Save');
49
+ $tcmp->Form->formEnds();
50
  }
includes/admin/whatsnew.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ define('TCMP_WHATSNEW_VERSION', 8);
3
+ function tcmp_ui_whats_new() {
4
+ global $tcmp;
5
+ $tcmp->Options->setShowWhatsNew(FALSE);
6
+ $tcmp->Options->setShowWhatsNewSeenVersion(TCMP_WHATSNEW_VERSION);
7
+ ?>
8
+ <style>
9
+ .tcmp-grid {
10
+ margin-left: auto;
11
+ margin-right: auto;
12
+ border-spacing: 10px;
13
+ max-width: 1120px;
14
+ }
15
+ .tcmp-grid td, .tcmp-grid td p {
16
+ font-size:16px;
17
+ vertical-align: top;
18
+ }
19
+ .tcmp-grid td ul {
20
+ list-style-type: disc;
21
+ margin-left: 30px!important;
22
+ }
23
+ .tcmp-grid td {
24
+ padding: 20px!important;
25
+ }
26
+ .tcmp-headline {
27
+ font-size:40px;
28
+ font-weight:bold;
29
+ text-align:center;
30
+ margin: 10px!important;
31
+ }
32
+ .tcmp-subheadline {
33
+ font-size:25px!important;
34
+ font-weight:bold;
35
+ text-align:left;
36
+ margin: 0px!important;
37
+ }
38
+ </style>
39
+
40
+ <p class="tcmp-headline">What's new in Tracking Code Manager?</p>
41
+ <table border="0" class="tcmp-grid">
42
+ <tr valign="top">
43
+ <td valign="top" width="50%">
44
+ Now the Tracking Code Manager let you:
45
+ <ul>
46
+ <li>Use tracking codes by device types</li>
47
+ <li>Sort tracking codes using drag & drop</li>
48
+ <li>Shortcode support</li>
49
+ <li>Fixed 6 small issues</li>
50
+ <li>Quick support links added</li>
51
+ </ul>
52
+ <br>
53
+
54
+ <p class="tcmp-subheadline">Dynamic Conversion Values</p>
55
+ <p>Finally, Dynamic Conversion Values are now available for WooCommerce and Easy Digital Download. Now you can track the values of your conversions on <b>Google Adwords</b> and <b>Facebook Ads</b> (with the <b>New Pixel</b> and relative events like "Purchase" and others), and many other channels.</p>
56
+ <img src="<?php echo TCMP_PLUGIN_ASSETS_URI ?>landing/tcmp-fb.png" />
57
+ <br>
58
+ <br>
59
+ <div style="float: right;">
60
+ <a class="button button-secondary" href="<?php echo TCMP_TAB_MANAGER_URI?>&hwb=1">CONTINUE USING FREE VERSION</a>
61
+ <a class="button button-primary" href="<?php echo TCMP_TAB_DOCS_DCV_URI?>?utm_campaign=whatsnew" target="_blank">SEE MORE ››</a>
62
+ </div>
63
+ </td>
64
+ <td valign="top" width="50%" style="border-left: 1px solid #44444E;">
65
+ <p class="tcmp-subheadline" style="margin-top: 0px!important;">Introducing the Tracking Code Manager brother!</p>
66
+ <p>We are proud to introduce Posts' Footer Manager, a free plugin that let you clean and organize the stuff you have in the footer of your blogpost.</p>
67
+ <p>If you are tired of the MESSY stuff that appears after the content of your pages and articles, you should give it a go.</p>
68
+ <div style="float: right;">
69
+ <a class="button button-secondary" href="http://wordpress.org/plugins/intelly-posts-footer-manager" target="_blank">
70
+ Download Posts' Footer Manager from Wordpress.org ››
71
+ </a>
72
+ </div>
73
+ <br>
74
+ <br>
75
+ <br>
76
+
77
+ <p class="tcmp-subheadline">Our new awesome Plugins:</p>
78
+ <p>Built by Marketers, for Marketers.</p>
79
+ <ul>
80
+ <li><a href="https://intellywp.com/custom-audiences-enhancer/?utm_campaign=whatsnew" target="_blank">Custom Audiences Enhancer</a></li>
81
+ <li><a href="https://wordpress.org/plugins/intelly-welcome-bar/" target="_blank">Welcome Bar</a></li>
82
+ <li><a href="https://wordpress.org/plugins/intelly-related-posts/" target="_blank">Inline Related Posts</a></li>
83
+ <li><a href="https://wordpress.org/plugins/intelly-countdown/" target="_blank">Evergreen Countdown Timer</a></li>
84
+ <li><a href="https://wordpress.org/plugins/intelly-posts-footer-manager/" target="_blank">Posts' Footer Manager</a></li>
85
+ </ul>
86
+ </td>
87
+ </tr>
88
+ </table>
89
+ <?php }
includes/class-TCM-cron.php DELETED
@@ -1,83 +0,0 @@
1
- <?php
2
- /**
3
- * Cron
4
- *
5
- * @package EDD
6
- * @subpackage Classes/Cron
7
- * @copyright Copyright (c) 2015, Pippin Williamson
8
- * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9
- * @since 1.6
10
- */
11
-
12
- // Exit if accessed directly
13
- if ( ! defined( 'ABSPATH' ) ) exit;
14
-
15
- class TCM_Cron {
16
- /**
17
- * Get things going
18
- *
19
- * @since 1.6
20
- * @see EDD_Cron::weekly_events()
21
- */
22
- public function __construct() {
23
- add_filter( 'cron_schedules', array( $this, 'add_schedules' ) );
24
- add_action( 'wp', array( $this, 'schedule_Events' ) );
25
- }
26
-
27
- /**
28
- * Registers new cron schedules
29
- *
30
- * @since 1.6
31
- *
32
- * @param array $schedules
33
- * @return array
34
- */
35
- public function add_schedules( $schedules = array() ) {
36
- global $tcm;
37
- // Adds once weekly to the existing schedules.
38
- $schedules['weekly'] = array(
39
- 'interval' => 604800,
40
- 'display' => $tcm->Lang->L('Once Weekly')
41
- );
42
-
43
- return $schedules;
44
- }
45
-
46
- /**
47
- * Schedules our events
48
- *
49
- * @access public
50
- * @since 1.6
51
- * @return void
52
- */
53
- public function schedule_Events() {
54
- $this->weekly_events();
55
- $this->daily_events();
56
- }
57
-
58
- /**
59
- * Schedule weekly events
60
- *
61
- * @access private
62
- * @since 1.6
63
- * @return void
64
- */
65
- private function weekly_events() {
66
- if ( ! wp_next_scheduled( 'tcm_weekly_scheduled_events' ) ) {
67
- wp_schedule_event( current_time( 'timestamp' ), 'weekly', 'tcm_weekly_scheduled_events' );
68
- }
69
- }
70
-
71
- /**
72
- * Schedule daily events
73
- *
74
- * @access private
75
- * @since 1.6
76
- * @return void
77
- */
78
- private function daily_events() {
79
- if ( ! wp_next_scheduled( 'tcm_daily_scheduled_events' ) ) {
80
- wp_schedule_event( current_time( 'timestamp' ), 'daily', 'tcm_daily_scheduled_events' );
81
- }
82
- }
83
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/class-TCM-form.php DELETED
@@ -1,298 +0,0 @@
1
- <?php
2
- /**
3
- * Created by PhpStorm.
4
- * User: alessio
5
- * Date: 28/03/2015
6
- * Time: 10:20
7
- */
8
- if ( ! defined( 'ABSPATH' ) ) exit;
9
-
10
- class TCM_Form {
11
- var $prefix='Form';
12
- var $labels=TRUE;
13
- var $leftLabels=TRUE;
14
- var $newline;
15
-
16
- var $leftTags=FALSE;
17
-
18
- public function __construct() {
19
- }
20
-
21
- //args can be a string or an associative array if you want
22
- private function parseArgs($args, $defaults) {
23
- $result=$args;
24
- if(is_array($result) && count($result)>0) {
25
- $result='';
26
- foreach($args as $k=>$v) {
27
- $result.=' '.$k.'="'.$v.'"';
28
- }
29
- } elseif(!$args) {
30
- $result='';
31
- }
32
- if(is_array($defaults) && count($defaults)>0) {
33
- foreach($defaults as $k=>$v) {
34
- if(stripos($result, $k.'=')===FALSE) {
35
- $result.=' '.$k.'="'.$v.'"';
36
- }
37
- }
38
- }
39
- return $result;
40
- }
41
-
42
- public function label($name, $args='') {
43
- global $tcm;
44
- $defaults=array('class'=>'');
45
- $other=$this->parseArgs($args, $defaults);
46
-
47
- $k=$this->prefix.'.'.$name;
48
- $label=$tcm->Lang->L($k);
49
-
50
- //check if is a mandatory field by checking the .txt language file
51
- $k=$this->prefix.'.'.$name.'.check';
52
- if($tcm->Lang->H($k)) {
53
- $label.=' (*)';
54
- }
55
-
56
- $aClass='';
57
- ?>
58
- <label for="<?php echo $name?>" <?php echo $other?> >
59
- <span style="float:left; margin-right:5px;" class="<?php echo $aClass?>"><?php echo $label?></span>
60
- </label>
61
- <?php }
62
-
63
- public function leftInput($name, $args='') {
64
- if(!$this->labels) return;
65
- if($this->leftLabels) {
66
- $this->label($name, $args);
67
- }
68
-
69
- if($this->newline) {
70
- $this->newline();
71
- }
72
- }
73
-
74
- public function newline() {
75
- ?><div class="tcm-form-newline"></div><?php
76
- }
77
-
78
- public function rightInput($name, $args='') {
79
- if(!$this->labels) return;
80
- if (!$this->leftLabels) {
81
- $this->label($name, $args);
82
- }
83
- $this->newline();
84
- }
85
-
86
- public function formStarts($method='post', $action='', $args=NULL) {
87
- //$defaults=array('style'=>'margin:1em 0; padding:1px 1em; background:#fff; border:1px solid #ccc;'
88
- $defaults=array('class'=>'tcm-form');
89
- $other=$this->parseArgs($args, $defaults);
90
- ?>
91
- <form method="<?php echo $method?>" action="<?php echo $action?>" <?php echo $other?> >
92
- <?php }
93
-
94
- public function formEnds() { ?>
95
- </form>
96
- <?php }
97
-
98
- public function divStarts($args=array()) {
99
- $defaults=array();
100
- $other=$this->parseArgs($args, $defaults);
101
- ?>
102
- <div <?php echo $other?>>
103
- <?php }
104
- public function divEnds() { ?>
105
- </div>
106
- <div style="clear:both;"></div>
107
- <?php }
108
-
109
- public function p($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
110
- global $tcm;
111
- ?>
112
- <p style="font-weight:bold;">
113
- <?php
114
- $tcm->Lang->P($message, $v1, $v2, $v3, $v4, $v5);
115
- if($tcm->Lang->H($message.'Subtitle')) { ?>
116
- <br/>
117
- <span style="font-weight:normal;">
118
- <?php $tcm->Lang->P($message.'Subtitle', $v1, $v2, $v3, $v4, $v5)?>
119
- </span>
120
- <?php } ?>
121
- </p>
122
- <?php }
123
-
124
- public function textarea($name, $value='', $args=NULL) {
125
- if(is_array($value) && isset($value[$name])) {
126
- $value=$value[$name];
127
- }
128
- $defaults=array('rows'=>10, 'class'=>'tcm-textarea');
129
- $other=$this->parseArgs($args, $defaults);
130
-
131
- $args=array('class'=>'tcm-label', 'style'=>'width:auto;');
132
- $this->newline=TRUE;
133
- $this->leftInput($name, $args);
134
- ?>
135
- <textarea dir="ltr" dirname="ltr" id="<?php echo $name ?>" name="<?php echo $name?>" <?php echo $other?> ><?php echo $value ?></textarea>
136
- <?php
137
- $this->newline=FALSE;
138
- $this->rightInput($name, $args);
139
- }
140
-
141
- public function text($name, $value='', $args=NULL) {
142
- if(is_array($value) && isset($value[$name])) {
143
- $value=$value[$name];
144
- }
145
- $defaults=array('class'=>'tcm-text');
146
- $other=$this->parseArgs($args, $defaults);
147
-
148
- $args=array('class'=>'tcm-label');
149
- $this->leftInput($name, $args);
150
- ?>
151
- <input type="text" id="<?php echo $name ?>" name="<?php echo $name ?>" value="<?php echo $value ?>" <?php echo $other?> />
152
- <?php
153
- $this->rightInput($name, $args);
154
- }
155
-
156
- public function hidden($name, $value='', $args=NULL) {
157
- if(is_array($value) && isset($value[$name])) {
158
- $value=$value[$name];
159
- }
160
- $defaults=array();
161
- $other=$this->parseArgs($args, $defaults);
162
- ?>
163
- <input type="hidden" id="<?php echo $name ?>" name="<?php echo $name ?>" value="<?php echo $value ?>" <?php echo $other?> />
164
- <?php }
165
-
166
- public function nonce($action=-1, $name='_wpnonce', $referer=true, $echo=true) {
167
- wp_nonce_field($action, $name, $referer, $echo);
168
- }
169
-
170
- public function select($name, $value, $options, $multiple, $args=NULL) {
171
- global $tcm;
172
- if(is_array($value) && isset($value[$name])) {
173
- $value=$value[$name];
174
- }
175
- $defaults=array('class'=>'tcm-select tcmTags');
176
- $other=$this->parseArgs($args, $defaults);
177
-
178
- if(!is_array($value)) {
179
- $value=array($value);
180
- }
181
- if(is_string($options)) {
182
- $options=explode(',', $options);
183
- }
184
- if(is_array($options) && count($options)>0) {
185
- if(!isset($options[0]['id'])) {
186
- //this is a normal array so I use the values for "id" field and the "name" into the txt file
187
- $temp=array();
188
- foreach($options as $v) {
189
- $temp[]=array('id'=>$v, 'name'=>$tcm->Lang->L($this->prefix.'.'.$name.'.'.$v));
190
- }
191
- $options=$temp;
192
- }
193
- }
194
-
195
- $args=array('class'=>'tcm-label');
196
- $this->leftInput($name, $args);
197
- ?>
198
- <select id="<?php echo $name ?>" name="<?php echo $name?><?php echo ($multiple ? '[]' : '')?>" <?php echo ($multiple ? 'multiple' : '')?> <?php echo $other?> >
199
- <?php
200
- foreach($options as $v) {
201
- $selected='';
202
- if(in_array($v['id'], $value)) {
203
- $selected=' selected="selected"';
204
- }
205
- ?>
206
- <option value="<?php echo $v['id']?>" <?php echo $selected?>><?php echo $v['name']?></option>
207
- <?php } ?>
208
- </select>
209
- <?php
210
- $this->rightInput($name, $args);
211
- }
212
-
213
- public function submit($value='', $args=NULL) {
214
- global $tcm;
215
- $defaults=array();
216
- $other=$this->parseArgs($args, $defaults);
217
- if($value=='') {
218
- $value='Send';
219
- }
220
- $this->newline();
221
- ?>
222
- <input type="submit" class="button-primary tcm-button tcm-submit" value="<?php $tcm->Lang->P($value)?>" <?php echo $other?>/>
223
- <?php }
224
-
225
- public function delete($id, $action='delete', $args=NULL) {
226
- global $tcm;
227
- $defaults=array();
228
- $other=$this->parseArgs($args, $defaults);
229
- ?>
230
- <input type="button" class="button tcm-button" value="<?php $tcm->Lang->P('Delete?')?>" onclick="if (confirm('<?php $tcm->Lang->P('Are you sure you want to delete?')?>') ) window.location='<?php echo TCM_TAB_MANAGER_URI?>&action=<?php echo $action?>&id=<?php echo $id ?>&amp;tcm_nonce=<?php echo esc_attr(wp_create_nonce('tcm_delete')); ?>';" <?php echo $other?> />
231
- &nbsp;
232
- <?php
233
- }
234
-
235
- public function checkbox($name, $current=1, $value=1, $args=NULL) {
236
- global $tcm;
237
- if(is_array($current) && isset($current[$name])) {
238
- $current=$current[$name];
239
- }
240
- $defaults=array('class'=>'tcm-checkbox', 'style'=>'margin:0px; margin-right:4px;');
241
- $other=$this->parseArgs($args, $defaults);
242
- $prev=$this->leftLabels;
243
- $this->leftLabels=FALSE;
244
-
245
- $args=array('class'=>'', 'style'=>'margin-top:-1px;');
246
- $this->leftInput($name, $args);
247
- ?>
248
- <input type="checkbox" id="<?php echo $name ?>" name="<?php echo $name?>" value="<?php echo $value?>" <?php echo($current!='' && $current==$value ? 'checked' : '') ?> <?php echo $other?> >
249
- <?php
250
- $this->rightInput($name, $args);
251
- $this->leftLabels=$prev;
252
- }
253
-
254
- public function checkText($nameActive, $nameText, $value) {
255
- global $tcm;
256
-
257
- $args=array('class'=>'tcm-hideShow tcm-checkbox'
258
- , 'tcm-hideIfTrue'=>'false'
259
- , 'tcm-hideShow'=>$nameText.'Text');
260
- $this->checkbox($nameActive, $value, 1, $args);
261
- ?>
262
- <div id="<?php echo $nameText?>Text" style="float:left;">
263
- <?php
264
- $prev=$this->labels;
265
- $this->labels=FALSE;
266
- $args=array();
267
- $this->text($nameText, $value, $args);
268
- $this->labels=$prev;
269
- ?>
270
- </div>
271
- <?php }
272
-
273
- //create a checkbox with a left select visible only when the checkbox is selected
274
- public function checkSelect($nameActive, $nameArray, $value, $values) {
275
- global $tcm;
276
- ?>
277
- <div id="<?php echo $nameArray?>Box" style="float:left;">
278
- <?php
279
- $args=array('class'=>'tcm-hideShow tcm-checkbox'
280
- , 'tcm-hideIfTrue'=>'false'
281
- , 'tcm-hideShow'=>$nameArray.'Tags');
282
- $this->checkbox($nameActive, $value, 1, $args);
283
- if(TRUE) { ?>
284
- <div id="<?php echo $nameArray?>Tags" style="float:left;">
285
- <?php
286
- $prev=$this->labels;
287
- $this->labels=FALSE;
288
- $args=array('class'=>'tcm-select tcmLineTags');
289
- $this->select($nameArray, $value, $values, TRUE, $args);
290
- $this->labels=$prev;
291
- ?>
292
- </div>
293
- <?php } ?>
294
- </div>
295
- <?php
296
- $this->newline();
297
- }
298
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/class-TCM-language.php DELETED
@@ -1,125 +0,0 @@
1
- <?php
2
- if ( ! defined( 'ABSPATH' ) ) exit;
3
-
4
- class TCM_Language {
5
- var $domain;
6
- function load($domain, $file) {
7
- $this->domain=$domain;
8
- if(!file_exists($file)) {
9
- return;
10
- }
11
- $file=file_get_contents($file);
12
- if($file!=NULL && strlen($file)>0) {
13
- $bundle=array();
14
- $file=str_replace("\r\n", "\n", $file);
15
- $file=str_replace("\n\n", "\n", $file);
16
- $file=explode("\n", $file);
17
-
18
- foreach($file as $row) {
19
- $index=strpos($row, "=");
20
- if($index===FALSE) continue;
21
-
22
- $k=trim(substr($row, 0, $index));
23
- $v=trim(substr($row, $index+1));
24
- $bundle[$k]=$v;
25
- }
26
-
27
- global $wp_session;
28
- $wp_session['LanguageBundle_'.$domain]=$bundle;
29
- }
30
- }
31
- //echo the $tcm->Lang->L result
32
- function P($key, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
33
- $what=$this->L($key, $v1, $v2, $v3, $v4, $v5);
34
- echo $what;
35
- }
36
- //verify if the key is defined or not
37
- function H($key) {
38
- global $wp_session;
39
- $bundle=$wp_session['LanguageBundle_'.$this->domain];
40
- if($bundle==NULL || count($bundle)==0) {
41
- return FALSE;
42
- }
43
-
44
- $result=FALSE;
45
- if(isset($bundle[$key])) {
46
- $result=TRUE;
47
- } elseif(isset($bundle[$key.'1'])) {
48
- $result=TRUE;
49
- } else {
50
- //special way to call this function passing arguments
51
- //WTF_something means key=WTF and something as first argument
52
- if(strpos($result, '_')!==FALSE) {
53
- $what = explode('_', $result);
54
- $array = array();
55
- $text = '';
56
- for ($i = 0; $i < count($what); $i++) {
57
- if ($i % 2 == 0) {
58
- $text .= $what[$i];
59
- } else {
60
- $array[] = $what[$i];
61
- }
62
- }
63
- if (isset($bundle[$text])) {
64
- $result=TRUE;
65
- }
66
- }
67
- }
68
- return $result;
69
- }
70
- //read the key from a text file with its translation. Try to translate using __(
71
- function L($key, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
72
- global $wp_session;
73
- $bundle=$wp_session['LanguageBundle_'.$this->domain];
74
- $result = $key;
75
- $args = array($v1, $v2, $v3, $v4, $v5);
76
-
77
- if($bundle==NULL || count($bundle)==0) {
78
- $result=__($result, $this->domain);
79
- } else {
80
- //i use the file to store the translations without writing it inside the code
81
- if (isset($bundle[$key])) {
82
- $result = $bundle[$key];
83
- $result = __($result, $this->domain);
84
- } elseif (isset($bundle[$key . '1'])) {
85
- $result = '';
86
- $n = 1;
87
- while (isset($bundle[$key . $n])) {
88
- if ($result != '') {
89
- $result .= '<br/>';
90
- }
91
- $result .= __($bundle[$key . $n], $this->domain);
92
- ++$n;
93
- }
94
- } else {
95
- //special way to call this function passing arguments
96
- //WTF_something means key=WTF and something as first argument
97
- if (strpos($result, '_') !== FALSE) {
98
- $what = explode('_', $result);
99
- $array = array();
100
- $text = '';
101
- for ($i = 0; $i < count($what); $i++) {
102
- if ($i % 2 == 0) {
103
- $text .= $what[$i];
104
- } else {
105
- $array[] = $what[$i];
106
- }
107
- }
108
- if (isset($bundle[$text])) {
109
- $result = $bundle[$text];
110
- $args = $array;
111
- }
112
- }
113
- $result = __($result, $this->domain);
114
- }
115
- }
116
- //here i translate it using WP
117
- foreach($args as $k=>$v) {
118
- $k='{'.$k.'}';
119
- while(strpos($result, $k)!==FALSE) {
120
- $result=str_replace($k, $v, $result);
121
- }
122
- }
123
- return $result;
124
- }
125
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/class-TCM-manager.php DELETED
@@ -1,321 +0,0 @@
1
- <?php
2
-
3
- // Exit if accessed directly
4
- if ( ! defined( 'ABSPATH' ) ) exit;
5
-
6
- class TCM_Manager {
7
-
8
- public function __construct() {
9
-
10
- }
11
-
12
- public function exists($name) {
13
- $snippets = $this->values();
14
- $result = NULL;
15
- $name=strtoupper($name);
16
- if (isset($snippets[$name])) {
17
- $result=$snippets[$name];
18
- }
19
- return $result;
20
- }
21
-
22
- //get a code snippet
23
- public function get($id, $new = FALSE) {
24
- global $tcm;
25
-
26
- $snippet=$tcm->Options->getSnippet($id);
27
- if (!$snippet && $new) {
28
- $snippet=array();
29
- $snippet['active']=1;
30
- $snippet['includeEverywhereActive']=1;
31
- }
32
-
33
- $snippet=$this->sanitize($id, $snippet);
34
- return $snippet;
35
- }
36
-
37
- private function sanitize($id, $snippet) {
38
- global $tcm;
39
- if($snippet==NULL || !is_array($snippet)) return;
40
-
41
- $defaults=array(
42
- 'id'=>$id
43
- , 'active'=>0
44
- , 'name'=>''
45
- , 'code'=>''
46
- , 'position'=>TCM_POSITION_HEAD
47
- , 'includeEverywhereActive'=>0
48
- );
49
-
50
- $types=$tcm->Utils->query(TCM_QUERY_POST_TYPES);
51
- foreach($types as $v) {
52
- $defaults['includePostsOfType_'.$v['name'].'_Active']=0;
53
- $defaults['includePostsOfType_'.$v['name']]=array();
54
- $defaults['exceptPostsOfType_'.$v['name'].'_Active']=0;
55
- $defaults['exceptPostsOfType_'.$v['name']]=array();
56
- }
57
- $snippet=$tcm->Utils->parseArgs($snippet, $defaults);
58
- //$snippet['includeLastPosts'] = intval($snippet['includeLastPosts']);
59
-
60
- foreach ($snippet as $k => $v) {
61
- if (stripos($k, 'active') !== FALSE) {
62
- $snippet[$k]=intval($v);
63
- } elseif (is_array($v)) {
64
- switch ($k) {
65
- /*
66
- case 'includePostsTypes':
67
- case 'excludePostsTypes':
68
- //keys are string and not number
69
- $result = $this->uarray($snippet, $k, FALSE);
70
- break;
71
- */
72
- default:
73
- //keys are number
74
- $result = $this->uarray($snippet, $k, TRUE);
75
- break;
76
- }
77
- }
78
- }
79
- $snippet['code']=trim($snippet['code']);
80
- $snippet['position']=intval($snippet['position']);
81
-
82
- $code=strtolower($snippet['code']);
83
- $cnt=substr_count($code, '<iframe')+substr_count($code, '<script');
84
- if($cnt<=0) {
85
- $cnt=1;
86
- }
87
- $snippet['codesCount']=$cnt;
88
- return $snippet;
89
- }
90
- private function uarray($snippet, $key, $isInteger = TRUE) {
91
- $array = $snippet[$key];
92
- if (!is_array($array)) {
93
- $array = explode(',', $array);
94
- }
95
-
96
- if ($isInteger) {
97
- for ($i = 0; $i < count($array); $i++) {
98
- $array[$i] = intval($array[$i]);
99
- }
100
- }
101
-
102
- $array = array_unique($array);
103
- $snippet[$key] = $array;
104
- return $snippet;
105
- }
106
-
107
- public function rc() {
108
- global $tcm;
109
- $result = 6-$this->codesCount();
110
- return $result;
111
- }
112
-
113
- //add or update a snippet (html tracking code)
114
- public function put($id, $snippet) {
115
- global $tcm;
116
-
117
- if ($id == '' || intval($id) <= 0) {
118
- //if is a new code create a new unique id
119
- $id = $this->getLastId() + 1;
120
- $snippet['id'] = $id;
121
- }
122
- $snippet=$this->sanitize($id, $snippet);
123
- $tcm->Options->setSnippet($id, $snippet);
124
-
125
- $keys = $this->keys();
126
- if (is_array($keys) && !in_array($id, $keys)) {
127
- $keys[] = $id;
128
- $this->keys($keys);
129
- }
130
- return $snippet;
131
- }
132
-
133
- //remove the id snippet
134
- public function remove($id) {
135
- global $tcm;
136
- $tcm->Options->removeSnippet($id);
137
- $keys=$this->keys();
138
- $result = FALSE;
139
- if (is_array($keys) && in_array($id, $keys)) {
140
- $keys = array_diff($keys, array($id));
141
- $this->keys($keys);
142
- $result = TRUE;
143
- }
144
- return $result;
145
- }
146
-
147
- //verify if match with this snippet
148
- private function matchSnippet($postId, $postType, $categoriesIds, $tagsIds, $prefix, $snippet) {
149
- global $tcm;
150
-
151
- $include=FALSE;
152
- $postId=intval($postId);
153
- if($postId>0) {
154
- $what=$prefix.'PostsOfType_'.$postType;
155
- if(!$include && $snippet[$what.'_Active'] && $tcm->Utils->inArray($postId, $snippet[$what])) {
156
- $tcm->Logger->debug('MATCH=%s SNIPPET=%s[%s] DUE TO POST=%s OF TYPE=%s IN [%s]'
157
- , $prefix, $snippet['id'], $snippet['name'], $postId, $postType, $snippet[$what]);
158
- $include=TRUE;
159
- }
160
- }
161
-
162
- return $include;
163
- }
164
-
165
- public function writeCodes($position) {
166
- global $tcm;
167
-
168
- $text='';
169
- switch ($position) {
170
- case TCM_POSITION_HEAD:
171
- $text='HEAD';
172
- break;
173
- case TCM_POSITION_BODY:
174
- $text='BODY';
175
- break;
176
- case TCM_POSITION_FOOTER:
177
- $text='FOOTER';
178
- break;
179
- }
180
-
181
- $post=$tcm->Options->getPostShown();
182
- $args=array('field'=>'code');
183
- $codes=$tcm->Manager->getCodes($position, $post, $args);
184
- if(is_array($codes) && count($codes)>0) {
185
- echo "\n<!--BEGIN: TRACKING CODE MANAGER BY INTELLYWP.COM IN $text//-->";
186
- foreach($codes as $v) {
187
- echo "\n$v";
188
- }
189
- echo "\n<!--END: TRACKING CODE MANAGER BY INTELLYWP.COM IN $text//-->";
190
- }
191
- }
192
-
193
- //from a post retrieve the html code that is needed to insert into the page code
194
- public function getCodes($position, $post, $args=array()) {
195
- global $tcm;
196
-
197
- $defaults=array('metabox'=>FALSE, 'field'=>'code');
198
- $args=wp_parse_args($args, $defaults);
199
-
200
- $postId=0;
201
- $postType='page';
202
- $tagsIds=array();
203
- $categoriesIds=array();
204
- if($post) {
205
- $postId = $post->ID;
206
- $postType = $post->post_type;
207
- }
208
-
209
- $tcm->Options->clearSnippetsWritten();
210
- $keys=$this->keys();
211
- foreach ($keys as $id) {
212
- $v=$this->get($id);
213
- if(!$v || ($position>-1 && $v['position']!=$position) || $v['code']=='' || (!$args['metabox'] && !$v['active'])) {
214
- continue;
215
- }
216
- if($tcm->Options->hasSnippetWritten($v)) {
217
- $tcm->Logger->debug('SKIPPED SNIPPET=%s[%s] DUE TO ALREADY WRITTEN', $v['id'], $v['name']);
218
- continue;
219
- }
220
-
221
- $match=FALSE;
222
- if(!$match && $v['includeEverywhereActive']) {
223
- $tcm->Logger->debug('INCLUDED SNIPPET=%s[%s] DUE TO EVERYWHERE', $v['id'], $v['name']);
224
- $match=TRUE;
225
- }
226
- if(!$match && $postId>0 && $this->matchSnippet($postId, $postType, $categoriesIds, $tagsIds, 'include', $v)) {
227
- $match=TRUE;
228
- }
229
-
230
- if($match && $postId>0) {
231
- if($this->matchSnippet($postId, $postType, $categoriesIds, $tagsIds, 'except', $v)) {
232
- $tcm->Logger->debug('FOUND AT LEAST ON EXCEPT TO EXCLUDE SNIPPET=%s [%s]', $v['id'], $v['name']);
233
- $match=FALSE;
234
- }
235
- }
236
-
237
- if ($match) {
238
- $tcm->Options->pushSnippetWritten($v);
239
- }
240
- }
241
-
242
- //obtain result as snippets or array of one field (tipically "id")
243
- $result=$tcm->Options->getSnippetsWritten();
244
- if ($args['field']!='all') {
245
- $array=array();
246
- foreach($result as $k=>$v) {
247
- $k=$args['field'];
248
- if(isset($v[$k])) {
249
- $array[]=$v[$k];
250
- } else {
251
- $tcm->Logger->error('SNIPPET=%s [%s] WITHOUT FIELD=%s', $v['id'], $v['name'], $k);
252
- }
253
- }
254
- $result=$array;
255
- }
256
- return $result;
257
- }
258
-
259
- //ottiene o salva tutte le chiavi dei tracking code utilizzati ordinati per id
260
- public function keys($keys=NULL) {
261
- global $tcm;
262
-
263
- if (is_array($keys)) {
264
- $tcm->Options->setSnippetList($keys);
265
- $result=$keys;
266
- } else {
267
- $result=$tcm->Options->getSnippetList();
268
- }
269
-
270
- if (!is_array($result)) {
271
- $result = array();
272
- } else {
273
- sort($result);
274
- }
275
- return $result;
276
- }
277
-
278
- //ottiene il conteggio attuale dei tracking code
279
- public function count() {
280
- $result = count($this->keys());
281
- return $result;
282
- }
283
- public function codesCount() {
284
- $result=0;
285
- $ids=$this->keys();
286
- foreach($ids as $id) {
287
- $snippet=$this->get($id);
288
- if($snippet) {
289
- if($snippet['codesCount']>0) {
290
- $result+=intval($snippet['codesCount']);
291
- } else {
292
- $result+=1;
293
- }
294
- }
295
- }
296
- return $result;
297
- }
298
- public function getLastId() {
299
- $result = 0;
300
- $list = $this->keys();
301
- foreach ($list as $v) {
302
- $v = intval($v);
303
- if ($v > $result) {
304
- $result = $v;
305
- }
306
- }
307
- return $result;
308
- }
309
-
310
- //ottiene tutti i tracking code ordinati per nome
311
- public function values() {
312
- $keys = $this->keys();
313
- $result = array();
314
- foreach ($keys as $k) {
315
- $v = $this->get($k);
316
- $result[strtoupper($v['name'])] = $v;
317
- }
318
- ksort($result);
319
- return $result;
320
- }
321
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/class-TCM-options.php DELETED
@@ -1,278 +0,0 @@
1
- <?php
2
- /**
3
- * Created by PhpStorm.
4
- * User: alessio
5
- * Date: 24/03/2015
6
- * Time: 08:45
7
- */
8
- // Exit if accessed directly
9
- if ( ! defined( 'ABSPATH' ) ) exit;
10
-
11
- class TCM_Options {
12
- public function __construct() {
13
-
14
- }
15
-
16
- //always add a prefix to avoid conflicts with other plugins
17
- private function getKey($key) {
18
- return 'TCM_'.$key;
19
- }
20
- //option
21
- private function removeOption($key) {
22
- $key=$this->getKey($key);
23
- delete_option($key);
24
- }
25
- private function getOption($key, $default=FALSE) {
26
- $key=$this->getKey($key);
27
- $result=get_option($key, $default);
28
- if(is_string($result)) {
29
- $result=trim($result);
30
- }
31
- return $result;
32
- }
33
- private function setOption($key, $value) {
34
- $key=$this->getKey($key);
35
- if(is_bool($value)) {
36
- $value=($value ? 1 : 0);
37
- }
38
- update_option($key, $value);
39
- }
40
-
41
- //$_SESSION
42
- private function removeSession($key) {
43
- global $wp_session;
44
-
45
- $key=$this->getKey($key);
46
- if(isset($wp_session[$key])) {
47
- unset($wp_session[$key]);
48
- }
49
- }
50
- private function getSession($key, $default=FALSE) {
51
- global $wp_session;
52
-
53
- $key=$this->getKey($key);
54
- $result=$default;
55
- if(isset($wp_session[$key])) {
56
- $result=$wp_session[$key];
57
- }
58
- if(is_string($result)) {
59
- $result=trim($result);
60
- }
61
- return $result;
62
- }
63
- private function setSession($key, $value) {
64
- global $wp_session;
65
-
66
- $key=$this->getKey($key);
67
- $wp_session[$key]=$value;
68
- }
69
-
70
- //$_REQUEST
71
- //However WP enforces its own logic - during load process wp_magic_quotes() processes variables to emulate magic quotes setting and enforces $_REQUEST to contain combination of $_GET and $_POST, no matter what PHP configuration says.
72
- private function removeRequest($key) {
73
- $key=$this->getKey($key);
74
- if(isset($_POST[$key])) {
75
- unset($_POST[$key]);
76
- }
77
- }
78
- private function getRequest($key, $default=FALSE) {
79
- $key=$this->getKey($key);
80
- $result=$default;
81
- if(isset($_POST[$key])) {
82
- $result=$_POST[$key];
83
- }
84
- return $result;
85
- }
86
- private function setRequest($key, $value) {
87
- $key=$this->getKey($key);
88
- $_POST[$key]=$value;
89
- }
90
-
91
- //TrackingEnable
92
- public function isTrackingEnable() {
93
- return $this->getOption('TrackingEnable', 0);
94
- }
95
- public function setTrackingEnable($value) {
96
- $this->setOption('TrackingEnable', $value);
97
- }
98
- //TrackingNotice
99
- public function isTrackingNotice() {
100
- return $this->getOption('TrackingNotice', 1);
101
- }
102
- public function setTrackingNotice($value) {
103
- $this->setOption('TrackingNotice', $value);
104
- }
105
-
106
- public function getTrackingLastSend() {
107
- return $this->getOption('TrackingLastSend['.TCM_PLUGIN_NAME.']', 0);
108
- }
109
- public function setTrackingLastSend($value) {
110
- $this->setOption('TrackingLastSend['.TCM_PLUGIN_NAME.']', $value);
111
- }
112
- public function getPluginInstallDate() {
113
- return $this->getOption('PluginInstallDate['.TCM_PLUGIN_NAME.']', 0);
114
- }
115
- public function setPluginInstallDate($value) {
116
- $this->setOption('PluginInstallDate['.TCM_PLUGIN_NAME.']', $value);
117
- }
118
- public function getPluginUpdateDate() {
119
- return $this->getOption('PluginUpdateDate['.TCM_PLUGIN_NAME.']', 0);
120
- }
121
- public function setPluginUpdateDate($value) {
122
- $this->setOption('PluginUpdateDate['.TCM_PLUGIN_NAME.']', $value);
123
- }
124
-
125
- //LoggerEnable
126
- public function isLoggerEnable() {
127
- return ($this->getOption('LoggerEnable', FALSE) || (defined('TCM_LOGGER') && TCM_LOGGER));
128
- }
129
- public function setLoggerEnable($value) {
130
- $this->setOption('LoggerEnable', $value);
131
- }
132
-
133
- //Snippet
134
- public function getSnippet($id) {
135
- return $this->getOption('Snippet_'.$id, NULL);
136
- }
137
- public function setSnippet($id, $value) {
138
- $this->setOption('Snippet_'.$id, $value);
139
- }
140
- public function removeSnippet($id) {
141
- $this->removeOption('Snippet_'.$id);
142
- }
143
- //SnippetList
144
- public function getSnippetList() {
145
- return $this->getOption('SnippetList', array());
146
- }
147
- public function setSnippetList($value) {
148
- $this->setOption('SnippetList', $value);
149
- }
150
- public function removeSnippetList() {
151
- $this->removeOption('SnippetList');
152
- }
153
-
154
- public function hasSnippetWritten($snippet) {
155
- //check also the md5 of code so if the user create 2 different snippets with
156
- //the same tracking code we will not insert into 2 times inside the html
157
- $id=$snippet['id'];
158
- $md5=md5($snippet['code']);
159
-
160
- $listIds=$this->getRequest('SnippetsWrittenIds', array());
161
- $listMd5=$this->getRequest('SnippetsWrittenMd5', array());
162
-
163
- $result=(in_array($id, $listIds) || in_array($md5, $listMd5));
164
- return $result;
165
- }
166
- public function pushSnippetWritten($snippet) {
167
- $md5=md5($snippet['code']);
168
- $id=$snippet['id'];
169
- $listIds=$this->getRequest('SnippetsWrittenIds', array());
170
- $listMd5=$this->getRequest('SnippetsWrittenMd5', array());
171
-
172
- $listIds[$id]=$snippet;
173
- $listMd5[$md5]=$id;
174
- $this->setRequest('SnippetsWrittenIds', $listIds);
175
- $this->setRequest('SnippetsWrittenMd5', $listMd5);
176
- }
177
- public function getSnippetsWritten() {
178
- return $this->getRequest('SnippetsWrittenIds', array());
179
- }
180
- public function clearSnippetsWritten() {
181
- $this->setRequest('SnippetsWrittenIds', array());
182
- $this->setRequest('SnippetsWrittenMd5', array());
183
- }
184
-
185
- //PostShown
186
- public function getPostShown() {
187
- return $this->getRequest('PostShown');
188
- }
189
- public function setPostShown($post) {
190
- $this->setRequest('PostShown', $post);
191
- }
192
- //Cache
193
- public function getCache($name, $id) {
194
- return $this->getRequest('Cache_'.$name.'_'.$id);
195
- }
196
- public function setCache($name, $id, $value) {
197
- $this->setRequest('Cache_'.$name.'_'.$id, $value);
198
- }
199
-
200
- //ErrorMessages
201
- public function hasErrorMessages() {
202
- $result=$this->getRequest('ErrorMessages', NULL);
203
- return (is_array($result) && count($result)>0);
204
- }
205
- public function pushErrorMessage($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
206
- global $tcm;
207
- $array=$this->getRequest('ErrorMessages', array());
208
- $array[]=$tcm->Lang->L($message, $v1, $v2, $v3, $v4, $v5);
209
- $this->setRequest('ErrorMessages', $array);
210
- }
211
- public function writeErrorMessages($clean=TRUE) {
212
- global $tcm;
213
- $array=$this->getRequest('ErrorMessages', array());
214
- if(is_array($array) && count($array)>0) { ?>
215
- <div class="message error"><?php echo wpautop(implode("\n", $array)); ?></div>
216
- <?php }
217
- if($clean) {
218
- $this->removeRequest('ErrorMessages');
219
- }
220
- }
221
- //SuccessMessages
222
- public function hasSuccessMessages() {
223
- $result=$this->getRequest('SuccessMessages', NULL);
224
- return (is_array($result) && count($result)>0);
225
- }
226
- public function pushSuccessMessage($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
227
- global $tcm;
228
- $array=$this->getRequest('SuccessMessages', array());
229
- $array[]=$tcm->Lang->L($message, $v1, $v2, $v3, $v4, $v5);
230
- $this->setRequest('SuccessMessages', $array);
231
- }
232
- public function writeSuccessMessages($clean=TRUE) {
233
- $array=$this->getRequest('SuccessMessages', array());
234
- if(is_array($array) && count($array)>0) { ?>
235
- <div class="message updated"><?php echo wpautop(implode("\n", $array)); ?></div>
236
- <?php }
237
- if($clean) {
238
- $this->removeRequest('SuccessMessages');
239
- }
240
- }
241
- public function writeMessages($clean=TRUE) {
242
- $this->writeErrorMessages($clean);
243
- $this->writeSuccessMessages($clean);
244
- }
245
- public function pushMessage($success, $message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
246
- if($success) {
247
- $this->pushSuccessMessage($message.'Success', $v1, $v2, $v3, $v4, $v5);
248
- } else {
249
- $this->pushErrorMessage($message.'Error', $v1, $v2, $v3, $v4, $v5);
250
- }
251
- }
252
-
253
- public function getFeedbackEmail() {
254
- return $this->getOption('FeedbackEmail', get_bloginfo('admin_email'));
255
- }
256
- public function setFeedbackEmail($value) {
257
- $this->setOption('FeedbackEmail', $value);
258
- }
259
-
260
- //MetaboxPostTypes
261
- public function getMetaboxPostTypes($create=TRUE) {
262
- global $tcm;
263
- $result=$this->getOption('MetaboxPostTypes', array());
264
- if($create) {
265
- $types=$tcm->Utils->query(TCM_QUERY_POST_TYPES);
266
- foreach($types as $v) {
267
- $v=$v['id'];
268
- if(!isset($result[$v])) {
269
- $result[$v]=1;
270
- }
271
- }
272
- }
273
- return $result;
274
- }
275
- public function setMetaboxPostTypes($values) {
276
- $this->setOption('MetaboxPostTypes', $values);
277
- }
278
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/class-TCM-utils.php DELETED
@@ -1,209 +0,0 @@
1
- <?php
2
- if ( ! defined( 'ABSPATH' ) ) exit;
3
-
4
- class TCM_Utils {
5
-
6
- function startsWith($haystack, $needle) {
7
- $length = strlen($needle);
8
- return (substr($haystack, 0, $length) === $needle);
9
- }
10
-
11
- function endsWith($haystack, $needle) {
12
- $length = strlen($needle);
13
- $start = $length * -1; //negative
14
- return (substr($haystack, $start) === $needle);
15
- }
16
- /**
17
- * Created by PhpStorm.
18
- * User: GIOVANNI
19
- * Date: 14/03/2015
20
- * Time: 15:47
21
- */
22
- //verifica se il parametro needle è un elemento dell'array haystack
23
- //se il parametro needle è a sua volta un array verifica che almeno un elemento
24
- //sia contenuto all'interno dell'array haystack
25
- function inArray($needle, $haystack) {
26
- if (is_string($haystack)) {
27
- //from string to numeric array
28
- $temp = explode(',', $haystack);
29
- $haystack = array();
30
- foreach ($temp as $v) {
31
- $v = trim($v);
32
- $v = intval($v);
33
- if ($v > 0) {
34
- $haystack[] = $v;
35
- }
36
- }
37
- }
38
-
39
- $result = FALSE;
40
- foreach ($haystack as $v) {
41
- $v = intval($v);
42
- //if one element of the array have -1 value means i select "all" option
43
- if ($v < 0) {
44
- $result = TRUE;
45
- break;
46
- }
47
- }
48
-
49
- if ($result) {
50
- return TRUE;
51
- }
52
-
53
- $result = FALSE;
54
- if (is_array($needle)) {
55
- foreach ($needle as $v) {
56
- $v = trim($v);
57
- $v = intval($v);
58
- if (in_array($v, $haystack)) {
59
- $result = TRUE;
60
- break;
61
- }
62
- }
63
- } else {
64
- //built-in comparison
65
- $result = in_array($needle, $haystack);
66
- }
67
- return $result;
68
- }
69
-
70
- function is($name, $compare, $default='', $ignoreCase=TRUE) {
71
- $what=$this->qs($name, $default);
72
- $result=FALSE;
73
- if(is_string($compare)) {
74
- $compare=explode(',', $compare);
75
- }
76
- if($ignoreCase){
77
- $what=strtolower($what);
78
- }
79
-
80
- foreach($compare as $v) {
81
- if($ignoreCase){
82
- $v=strtolower($v);
83
- }
84
- if($what==$v) {
85
- $result=TRUE;
86
- break;
87
- }
88
- }
89
- return $result;
90
- }
91
-
92
- public function twitter($name) {
93
- ?>
94
- <a href="https://twitter.com/<?php echo $name?>" class="twitter-follow-button" data-show-count="false" data-dnt="true">Follow @<?php echo $name?></a>
95
- <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
96
- <?php
97
- }
98
-
99
- //per ottenere un campo dal $_GET oppure dal $_POST
100
- function qs($name, $default = '') {
101
- $result = $default;
102
- if (isset($_GET[$name])) {
103
- $result = $_GET[$name];
104
- } elseif (isset($_POST[$name])) {
105
- $result = $_POST[$name];
106
- }
107
-
108
- if (is_string($result)) {
109
- $result = urldecode($result);
110
- $result = trim($result);
111
- }
112
-
113
- return $result;
114
- }
115
-
116
- function query($query, $args = NULL) {
117
- global $tcm;
118
-
119
- $defaults = array('post_type' => '', 'all' => FALSE);
120
- $args = wp_parse_args($args, $defaults);
121
-
122
- $result = $tcm->Options->getCache('Query', $query . '_' . $args['post_type']);
123
- if (!is_array($result) || count($result) == 0) {
124
- $q = NULL;
125
- $id = 'ID';
126
- $name = 'post_title';
127
- switch ($query) {
128
- case TCM_QUERY_POSTS_OF_TYPE:
129
- $options = array('posts_per_page' => -1, 'post_type' => $args['post_type']);
130
- $q = get_posts($options);
131
- break;
132
- }
133
-
134
- $result = array();
135
- if ($q) {
136
- foreach ($q as $v) {
137
- $result[] = array('id' => $v->$id, 'name' => $v->$name);
138
- }
139
- } elseif ($query == TCM_QUERY_POST_TYPES) {
140
- $q=array('post', 'page');
141
- sort($q);
142
- foreach ($q as $v) {
143
- $result[] = array('id' => $v, 'name' => $v);
144
- }
145
- }
146
-
147
- $tcm->Options->setCache('Query', $query . '_' . $args['post_type'], $result);
148
- }
149
-
150
- if ($args['all']) {
151
- $first = array();
152
- $first[] = array('id' => -1, 'name' => '[' . $tcm->Lang->L('All') . ']');
153
- $result = array_merge($first, $result);
154
- }
155
-
156
- return $result;
157
- }
158
-
159
- //send remote request to our server to store tracking and feedback
160
- function remotePost($action, $data = '') {
161
- global $tcm;
162
-
163
- $data['secret'] = 'WYSIWYG';
164
- $response = wp_remote_post(TCM_INTELLYWP_RECEIVER . '?iwpm_action=' . $action, array(
165
- 'method' => 'POST'
166
- , 'timeout' => 20
167
- , 'redirection' => 5
168
- , 'httpversion' => '1.1'
169
- , 'blocking' => TRUE
170
- , 'body' => $data
171
- , 'user-agent' => 'TCM/' . TCM_PLUGIN_VERSION . '; ' . get_bloginfo('url')
172
- ));
173
- $data = json_decode(wp_remote_retrieve_body($response), TRUE);
174
- if (is_wp_error($response) || wp_remote_retrieve_response_code($response) != 200
175
- || !isset($data['success']) || !$data['success']
176
- ) {
177
- $tcm->Logger->error('ERRORS SENDING REMOTE-POST ACTION=%s DUE TO REASON=%s', $action, $response);
178
- $data = FALSE;
179
- } else {
180
- $tcm->Logger->debug('SUCCESSFULLY SENT REMOTE-POST ACTION=%s RESPONSE=%s', $action, $data);
181
- }
182
- return $data;
183
- }
184
-
185
- //wp_parse_args with null correction
186
- function parseArgs($args, $defaults) {
187
- if (is_null($args) || !is_array($args)) {
188
- $args = array();
189
- }
190
- foreach ($args as $k => $v) {
191
- if (is_null($args[$k])) {
192
- //so can take the default value
193
- unset($args[$k]);
194
- } elseif (is_string($args[$k]) && $args[$k] == '' && isset($defaults[$k]) && is_array($defaults[$k])) {
195
- //a very strange case, i have a blank string for rappresenting an empty array
196
- unset($args[$k]);
197
- }
198
- }
199
- $result = wp_parse_args($args, $defaults);
200
- return $result;
201
- }
202
-
203
- function redirect($location) {
204
- //seems that if you have installed xdebug (or some version of it) doesnt work so js added
205
- wp_redirect($location);
206
- ?>
207
- <script> window.location.replace('<?php echo $location?>'); </script>
208
- <?php }
209
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/classes/core/Manager.php ADDED
@@ -0,0 +1,657 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ class TCMP_Manager {
5
+ public function __construct() {
6
+ }
7
+ public function init() {
8
+ add_action('wp_ajax_TCMP_changeOrder', array(&$this, 'changeOrder'));
9
+ }
10
+ public function isLimitReached($notice=TRUE) {
11
+ global $tcmp;
12
+ $cnt=$this->codesCount();
13
+ $result=($cnt>=TCMP_SNIPPETS_LIMIT);
14
+ if ($result && $notice) {
15
+ $tcmp->Options->pushWarningMessage('SnippetsLimitReached', TCMP_SNIPPETS_LIMIT, TCMP_PAGE_PREMIUM);
16
+ } elseif($notice && $cnt>0) {
17
+ $tcmp->Options->pushSuccessMessage('SnippetsLimitNotice', $cnt, TCMP_SNIPPETS_LIMIT, TCMP_PAGE_PREMIUM);
18
+ }
19
+ return $result;
20
+ }
21
+ public function changeOrder() {
22
+ global $tcmp;
23
+ if(!isset($_POST['order'])) {
24
+ return;
25
+ }
26
+
27
+ $data=array();
28
+ parse_str(TCMP_SQS('order'), $data);
29
+
30
+ if (isset($data['row'])) {
31
+ $snippets=$this->values();
32
+ foreach($snippets as $id=>$v) {
33
+ $v['order']=0;
34
+ $snippets[$id]=$v;
35
+ }
36
+
37
+ $index=1;
38
+ foreach($data['row'] as $order=>$id) {
39
+ $v=$snippets[$id];
40
+ $v['order']=$index;
41
+ $snippets[$id]=$v;
42
+ ++$index;
43
+ }
44
+
45
+ foreach($snippets as $id=>$v) {
46
+ $this->put($id, $v);
47
+ }
48
+ }
49
+ echo 'OK';
50
+ wp_die();
51
+ }
52
+
53
+ public function matchDeviceType($snippet) {
54
+ global $tcmp;
55
+ $deviceType=$tcmp->Utils->get($snippet, 'deviceType', FALSE);
56
+ $deviceType=$tcmp->Utils->toArray($deviceType);
57
+ if($deviceType===FALSE || count($deviceType)==0) {
58
+ return TRUE;
59
+ }
60
+
61
+ $detect=new TCMP_Mobile_Detect();
62
+ if ($detect->isMobile()) {
63
+ $type=TCMP_DEVICE_TYPE_MOBILE;
64
+ } elseif($detect->isTablet()){
65
+ $type=TCMP_DEVICE_TYPE_TABLET;
66
+ } else { //if(!$detect->isMobile() && !$detect->isTablet()) {
67
+ $type=TCMP_DEVICE_TYPE_DESKTOP;
68
+ }
69
+
70
+ $result=FALSE;
71
+ if(in_array(TCMP_DEVICE_TYPE_ALL, $deviceType) || in_array($type, $deviceType)) {
72
+ $result=TRUE;
73
+ }
74
+ return $result;
75
+ }
76
+ public function isModeScript($snippet) {
77
+ global $tcmp;
78
+ $result=$tcmp->Utils->iget($snippet, 'trackMode', 0);
79
+ return ($result==0);
80
+ }
81
+ public function isModeConversion($snippet) {
82
+ global $tcmp;
83
+ $result=$tcmp->Utils->iget($snippet, 'trackMode', 0);
84
+ return ($result!=0);
85
+ }
86
+ public function isPageEverywhere($snippet) {
87
+ global $tcmp;
88
+ if(!$this->isModeScript($snippet)) {
89
+ return FALSE;
90
+ }
91
+
92
+ $result=$tcmp->Utils->iget($snippet, 'trackPage', 0);
93
+ return ($result==TCMP_TRACK_PAGE_ALL);
94
+ }
95
+ public function isPageSpecific($snippet) {
96
+ global $tcmp;
97
+ if(!$this->isModeScript($snippet)) {
98
+ return FALSE;
99
+ }
100
+
101
+ $result=$tcmp->Utils->iget($snippet, 'trackPage', 0);
102
+ return ($result==TCMP_TRACK_PAGE_SPECIFIC);
103
+ }
104
+
105
+ public function exists($name) {
106
+ $snippets=$this->values();
107
+ $result=NULL;
108
+ $name=strtoupper($name);
109
+ if (isset($snippets[$name])) {
110
+ $result=$snippets[$name];
111
+ }
112
+ return $result;
113
+ }
114
+
115
+ //get a code snippet
116
+ public function get($id, $new=FALSE) {
117
+ global $tcmp;
118
+
119
+ $snippet=$tcmp->Options->getSnippet($id);
120
+ if (!$snippet && $new) {
121
+ $snippet=array();
122
+ $snippet['active']=1;
123
+ $snippet['trackMode']=-1;
124
+ $snippet['trackPage']=-1;
125
+ }
126
+
127
+ $snippet=$this->sanitize($id, $snippet);
128
+ return $snippet;
129
+ }
130
+
131
+ public function sanitize($id, $snippet) {
132
+ global $tcmp;
133
+ if($snippet==NULL || !is_array($snippet)) return NULL;
134
+
135
+ $page=0;
136
+ if(isset($snippet['includeEverywhereActive'])) {
137
+ $page=(intval($snippet['includeEverywhereActive']==1) ? 0 : 1);
138
+ }
139
+ $defaults=array(
140
+ 'id'=>$id
141
+ , 'active'=>0
142
+ , 'name'=>''
143
+ , 'code'=>''
144
+ , 'order'=>1000
145
+ , 'position'=>TCMP_POSITION_HEAD
146
+ , 'trackMode'=>TCMP_TRACK_MODE_CODE
147
+ , 'trackPage'=>$page
148
+ , 'includeEverywhereActive'=>0
149
+ , 'includeCategoriesActive'=>0
150
+ , 'includeCategories'=>array()
151
+ , 'includeTagsActive'=>0
152
+ , 'includeTags'=>array()
153
+ , 'exceptCategoriesActive'=>0
154
+ , 'exceptCategories'=>array()
155
+ , 'exceptTagsActive'=>0
156
+ , 'exceptTags'=>array()
157
+ , 'deviceType'=>TCMP_DEVICE_TYPE_ALL
158
+ );
159
+
160
+ $types=$tcmp->Utils->query(TCMP_QUERY_POST_TYPES);
161
+ foreach($types as $v) {
162
+ $defaults['includePostsOfType_'.$v['id'].'_Active']=0;
163
+ $defaults['includePostsOfType_'.$v['id']]=array();
164
+ $defaults['exceptPostsOfType_'.$v['id'].'_Active']=0;
165
+ $defaults['exceptPostsOfType_'.$v['id']]=array();
166
+ }
167
+
168
+ $types=$tcmp->Utils->query(TCMP_QUERY_CONVERSION_PLUGINS);
169
+ foreach($types as $v) {
170
+ //CP stands for ConversionTrackingCode
171
+ //$defaults['CTC_'.$v['id'].'_Active']=0;
172
+ $defaults['CTC_'.$v['id'].'_ProductsIds']=array();
173
+ $defaults['CTC_'.$v['id'].'_CategoriesIds']=array();
174
+ $defaults['CTC_'.$v['id'].'_TagsIds']=array();
175
+ }
176
+ $snippet=$tcmp->Utils->parseArgs($snippet, $defaults);
177
+
178
+ foreach ($snippet as $k => $v) {
179
+ if (stripos($k, 'active') !== FALSE) {
180
+ $snippet[$k]=intval($v);
181
+ } elseif (is_array($v)) {
182
+ switch ($k) {
183
+ /*
184
+ case 'includePostsTypes':
185
+ case 'excludePostsTypes':
186
+ //keys are string and not number
187
+ $result=$this->uarray($snippet, $k, FALSE);
188
+ break;
189
+ */
190
+ default:
191
+ //keys are number
192
+ $result=$this->uarray($snippet, $k, TRUE);
193
+ break;
194
+ }
195
+ }
196
+ }
197
+ $snippet['code']=trim($snippet['code']);
198
+ $snippet['position']=intval($snippet['position']);
199
+ if($snippet['trackMode']==='') {
200
+ $snippet['trackMode']=TCMP_TRACK_MODE_CODE;
201
+ } else {
202
+ $snippet['trackMode']=intval($snippet['trackMode']);
203
+ }
204
+ if($snippet['trackPage']==='') {
205
+ $snippet['trackPage']=$page;
206
+ } else {
207
+ $snippet['trackPage']=intval($snippet['trackPage']);
208
+ }
209
+
210
+ $snippet['includeEverywhereActive']=0;
211
+ if($snippet['trackPage']==TCMP_TRACK_PAGE_ALL) {
212
+ $snippet['includeEverywhereActive']=1;
213
+ }
214
+
215
+ $code=strtolower($snippet['code']);
216
+ $cnt=substr_count($code, '<iframe')+substr_count($code, '<script');
217
+ if($cnt<=0) {
218
+ $cnt=1;
219
+ }
220
+ $snippet['codesCount']=$cnt;
221
+ return $snippet;
222
+ }
223
+ private function uarray($snippet, $key, $isInteger=TRUE) {
224
+ $array=$snippet[$key];
225
+ if (!is_array($array)) {
226
+ $array=explode(',', $array);
227
+ }
228
+
229
+ if ($isInteger) {
230
+ for ($i=0; $i < count($array); $i++) {
231
+ $array[$i]=intval($array[$i]);
232
+ }
233
+ }
234
+
235
+ $array=array_unique($array);
236
+ $snippet[$key]=$array;
237
+ return $snippet;
238
+ }
239
+
240
+ //add or update a snippet (html tracking code)
241
+ public function put($id, $snippet) {
242
+ global $tcmp;
243
+
244
+ if ($id == '' || intval($id) <= 0) {
245
+ //if is a new code create a new unique id
246
+ $id=$this->getLastId() + 1;
247
+ $snippet['id']=$id;
248
+ }
249
+ $snippet=$this->sanitize($id, $snippet);
250
+ $tcmp->Options->setSnippet($id, $snippet);
251
+
252
+ $keys=$this->keys();
253
+ if (is_array($keys) && !in_array($id, $keys)) {
254
+ $keys[]=$id;
255
+ $this->keys($keys);
256
+ }
257
+ return $snippet;
258
+ }
259
+
260
+ //remove the id snippet
261
+ public function remove($id) {
262
+ global $tcmp;
263
+ $tcmp->Options->removeSnippet($id);
264
+ $keys=$this->keys();
265
+ $result=FALSE;
266
+ if (is_array($keys) && in_array($id, $keys)) {
267
+ $keys=array_diff($keys, array($id));
268
+ $this->keys($keys);
269
+ $result=TRUE;
270
+ }
271
+ return $result;
272
+ }
273
+
274
+ //verify if match with this snippet
275
+ private function matchSnippet($postId, $postType, $categoriesIds, $tagsIds, $prefix, $snippet) {
276
+ global $tcmp;
277
+ if(!$this->matchDeviceType($snippet)) {
278
+ return FALSE;
279
+ }
280
+
281
+ $include=FALSE;
282
+ $postId=intval($postId);
283
+ if($postId>0) {
284
+ $what=$prefix.'PostsOfType_'.$postType;
285
+ if(!$include && isset($snippet[$what.'_Active']) && isset($snippet[$what])&& $snippet[$what.'_Active'] && $tcmp->Utils->inAllArray($postId, $snippet[$what])) {
286
+ $tcmp->Log->debug('MATCH=%s SNIPPET=%s[%s] DUE TO POST=%s OF TYPE=%s IN [%s]'
287
+ , $prefix, $snippet['id'], $snippet['name'], $postId, $postType, $snippet[$what]);
288
+ $include=TRUE;
289
+ }
290
+ }
291
+
292
+ return $include;
293
+ }
294
+
295
+ public function writeCodes($position) {
296
+ global $tcmp;
297
+
298
+ $text='';
299
+ switch ($position) {
300
+ case TCMP_POSITION_HEAD:
301
+ $text='HEAD';
302
+ break;
303
+ case TCMP_POSITION_BODY:
304
+ $text='BODY';
305
+ break;
306
+ case TCMP_POSITION_FOOTER:
307
+ $text='FOOTER';
308
+ break;
309
+ case TCMP_POSITION_CONVERSION:
310
+ $text='CONVERSION';
311
+ break;
312
+ }
313
+
314
+ $post=$tcmp->Options->getPostShown();
315
+ $args=array('field'=>'code');
316
+ $codes=$tcmp->Manager->getCodes($position, $post, $args);
317
+ if(is_array($codes) && count($codes)>0) {
318
+ ob_start();
319
+ echo "\n<!--BEGIN: TRACKING CODE MANAGER BY INTELLYWP.COM IN $text//-->";
320
+ foreach($codes as $v) {
321
+ echo "\n$v";
322
+ }
323
+ echo "\n<!--END: https://wordpress.org/plugins/tracking-code-manager IN $text//-->";
324
+ $text=ob_get_contents();
325
+ ob_end_clean();
326
+
327
+ $purchase=$tcmp->Options->getEcommercePurchase();
328
+ if($purchase!==FALSE && intval($tcmp->Options->getLicenseSiteCount())>0) {
329
+ //retrieve user data
330
+ $purchase->userId=intval($purchase->userId);
331
+ if($purchase->userId>0) {
332
+ $user=get_user_by('id', $purchase->userId);
333
+ if(!is_null($user) && $user!==FALSE && get_class($user)=='WP_User') {
334
+ /* @var $user WP_User */
335
+ $purchase->email=$user->user_email;
336
+ $purchase->fullname=$user->user_firstname;
337
+ if($user->user_lastname!='') {
338
+ $purchase->fullname.=' '.$user->user_lastname;
339
+ }
340
+ }
341
+ }
342
+
343
+ $purchase->total=floatval($purchase->total);
344
+ $purchase->amount=floatval($purchase->amount);
345
+ $purchase->tax=floatval($purchase->tax);
346
+
347
+ $fields=array(
348
+ 'ORDERID'=>$purchase->orderId
349
+ , 'CURRENCY'=>$purchase->currency
350
+ , 'FULLNAME'=>$purchase->fullname
351
+ , 'EMAIL'=>$purchase->email
352
+ , 'PRODUCTS'=>$purchase->products
353
+ , 'AMOUNT'=>$purchase->amount
354
+ , 'TOTAL'=>$purchase->total
355
+ , 'TAX'=>$purchase->tax
356
+ );
357
+
358
+ $sep='@@';
359
+ $buffer='';
360
+ $previous=0;
361
+ $start=strpos($text, $sep);
362
+ if($start===FALSE) {
363
+ $buffer=$text;
364
+ } else {
365
+ while($start!==FALSE) {
366
+ $buffer.=$tcmp->Utils->substr($text, $previous, $start);
367
+ $end=strpos($text, $sep, $start+strlen($sep));
368
+ if($end!==FALSE) {
369
+ $code=$tcmp->Utils->substr($text, $start+strlen($sep), $end);
370
+ $code=$tcmp->Utils->toArray($code);
371
+ if(count($code)==1) {
372
+ $code[]='';
373
+ }
374
+
375
+ $v=FALSE;
376
+ if(isset($fields[$code[0]])) {
377
+ $v=$fields[$code[0]];
378
+ }
379
+ if(is_null($v) || $v===FALSE) {
380
+ $v=$code[1];
381
+ }
382
+ if(is_numeric($v)) {
383
+ $v=floatval($v);
384
+ $v=round($v, 2);
385
+ switch ($code[0]) {
386
+ case 'TOTAL':
387
+ case 'AMOUNT':
388
+ case 'TAX':
389
+ $v=number_format($v, 2, '.', '');
390
+ break;
391
+ default:
392
+ $v=intval($v);
393
+ break;
394
+ }
395
+ } elseif(is_array($v)) {
396
+ $a='';
397
+ foreach($v as $t) {
398
+ $t=str_replace(',', '', $t);
399
+ if($a!='') {
400
+ $a.=',';
401
+ }
402
+ $a.=$t;
403
+ }
404
+ $v=$a;
405
+ }
406
+ $v=str_replace("'", '', $v);
407
+ $v=str_replace('"', '', $v);
408
+ $buffer.=$v;
409
+
410
+ $previous=$end+strlen($sep);
411
+ $start=strpos($text, $sep, $previous);
412
+ } else {
413
+ $buffer.=$tcmp->Utils->substr($text, $start);
414
+ $previous=FALSE;
415
+ $start=FALSE;
416
+ }
417
+ }
418
+ }
419
+ if($previous!==FALSE && $previous<strlen($text)) {
420
+ $code=$tcmp->Utils->substr($text, $previous);
421
+ $buffer.=$code;
422
+ }
423
+ $text=$buffer;
424
+ }
425
+ echo $text;
426
+ }
427
+ }
428
+
429
+ //return snippets that match with options
430
+ public function getConversionSnippets($options=NULL) {
431
+ global $tcmp;
432
+
433
+ $defaults=array(
434
+ 'pluginId'=>0
435
+ , 'categoriesIds'=>array()
436
+ , 'productsIds'=>array()
437
+ , 'tagsIds'=>array()
438
+ );
439
+ $options=$tcmp->Utils->parseArgs($options, $defaults);
440
+
441
+ $result=array();
442
+ $pluginId=intval($options['pluginId']);
443
+ $values=$this->values();
444
+
445
+ foreach($values as $snippet) {
446
+ $snippet['trackMode']=intval($snippet['trackMode']);
447
+ if($snippet && $snippet['trackMode']>0 && $snippet['trackMode']==$pluginId) {
448
+ $match=FALSE;
449
+
450
+ $match=($match || $this->matchConversion($snippet, $pluginId, 'ProductsIds', $options['productsIds']));
451
+ $match=($match && $this->matchDeviceType($snippet));
452
+ if(!$match) {
453
+ //no selected so..all match! :)
454
+ if(count($snippet['CTC_'.$pluginId.'_ProductsIds'])==0
455
+ && count($snippet['CTC_'.$pluginId.'_CategoriesIds'])==0
456
+ && count($snippet['CTC_'.$pluginId.'_TagsIds'])==0) {
457
+ $match=TRUE;
458
+ }
459
+ }
460
+
461
+ if($match) {
462
+ $result[]=$snippet;
463
+ }
464
+ }
465
+ }
466
+ return $result;
467
+ }
468
+ private function matchConversion($snippet, $pluginId, $suffix, $currentIds) {
469
+ global $tcmp;
470
+
471
+ $settingsIds='CTC_'.$pluginId.'_'.$suffix;
472
+ if(isset($snippet[$settingsIds])) {
473
+ $settingsIds=$snippet[$settingsIds];
474
+ } else {
475
+ $settingsIds=array();
476
+ }
477
+
478
+ $result=$tcmp->Utils->inAllArray($currentIds, $settingsIds);
479
+ return $result;
480
+ }
481
+
482
+ //from a post retrieve the html code that is needed to insert into the page code
483
+ public function getCodes($position, $post, $args=array()) {
484
+ global $tcmp;
485
+
486
+ $defaults=array('field'=>'code');
487
+ $args=$tcmp->Utils->parseArgs($args, $defaults);
488
+
489
+ $postId=0;
490
+ $postType='page';
491
+ $tagsIds=array();
492
+ $categoriesIds=array();
493
+ if($post) {
494
+ $postId=$tcmp->Utils->get($post, 'ID', FALSE);
495
+ if($postId===FALSE) {
496
+ $postId=$tcmp->Utils->get($post, 'post_ID');
497
+ }
498
+ $postType=$tcmp->Utils->get($post, 'post_type');
499
+
500
+ $options=array('orderby' => 'name', 'order' => 'ASC', 'fields' => 'ids');
501
+ if(isset($post->ID)) {
502
+ $tagsIds=wp_get_post_tags($post->ID, $options);
503
+ $categoriesIds=wp_get_post_categories($post->ID);
504
+ } else {
505
+ $tagsIds=array();
506
+ $categoriesIds=array();
507
+ }
508
+ }
509
+
510
+ $tcmp->Options->clearSnippetsWritten();
511
+ if($position==TCMP_POSITION_CONVERSION) {
512
+ //write snippets previously appended
513
+ $ids=$tcmp->Options->getConversionSnippetIds();
514
+ if($ids!==FALSE && count($ids)>0) {
515
+ foreach($ids as $id) {
516
+ $snippet=$tcmp->Manager->get($id);
517
+ if($snippet) {
518
+ $tcmp->Options->pushSnippetWritten($snippet);
519
+ }
520
+ }
521
+ }
522
+ } else {
523
+ $snippets=$this->values();
524
+ foreach ($snippets as $v) {
525
+ if(!$v || ($position>-1 && $v['position']!=$position) || $v['code']=='' || !$v['active']) {
526
+ continue;
527
+ }
528
+ if ($v['trackMode']!=TCMP_TRACK_MODE_CODE) {
529
+ continue;
530
+ }
531
+ if($tcmp->Options->hasSnippetWritten($v)) {
532
+ $tcmp->Log->debug('SKIPPED SNIPPET=%s[%s] DUE TO ALREADY WRITTEN', $v['id'], $v['name']);
533
+ continue;
534
+ }
535
+
536
+ $match=FALSE;
537
+ if (!$match && ($v['trackPage']==TCMP_TRACK_PAGE_ALL || $v['includeEverywhereActive'])) {
538
+ $tcmp->Log->debug('INCLUDED SNIPPET=%s[%s] DUE TO EVERYWHERE', $v['id'], $v['name']);
539
+ $match=TRUE;
540
+ }
541
+ if(!$match && $postId>0 && $this->matchSnippet($postId, $postType, $categoriesIds, $tagsIds, 'include', $v)) {
542
+ $match=TRUE;
543
+ }
544
+
545
+ if($match && $postId>0) {
546
+ if($this->matchSnippet($postId, $postType, $categoriesIds, $tagsIds, 'except', $v)) {
547
+ $tcmp->Log->debug('FOUND AT LEAST ON EXCEPT TO EXCLUDE SNIPPET=%s [%s]', $v['id'], $v['name']);
548
+ $match=FALSE;
549
+ }
550
+ }
551
+
552
+ if ($match) {
553
+ $tcmp->Options->pushSnippetWritten($v);
554
+ }
555
+ }
556
+ }
557
+
558
+ //obtain result as snippets or array of one field (tipically "id")
559
+ $result=$tcmp->Options->getSnippetsWritten();
560
+ if ($args['field']!='all') {
561
+ $array=array();
562
+ foreach($result as $k=>$v) {
563
+ $k=$args['field'];
564
+ if(isset($v[$k])) {
565
+ $array[]=$v[$k];
566
+ } else {
567
+ $tcmp->Log->error('SNIPPET=%s [%s] WITHOUT FIELD=%s', $v['id'], $v['name'], $k);
568
+ }
569
+ }
570
+ $result=$array;
571
+ }
572
+ return $result;
573
+ }
574
+
575
+ //ottiene o salva tutte le chiavi dei tracking code utilizzati ordinati per id
576
+ public function keys($keys=NULL) {
577
+ global $tcmp;
578
+
579
+ if (is_array($keys)) {
580
+ $tcmp->Options->setSnippetList($keys);
581
+ $result=$keys;
582
+ } else {
583
+ $result=$tcmp->Options->getSnippetList();
584
+ }
585
+
586
+ if (!is_array($result)) {
587
+ $result=array();
588
+ } else {
589
+ sort($result);
590
+ }
591
+ return $result;
592
+ }
593
+
594
+ //ottiene il conteggio attuale dei tracking code
595
+ public function count() {
596
+ $result=count($this->keys());
597
+ return $result;
598
+ }
599
+ public function codesCount() {
600
+ $result=0;
601
+ $ids=$this->keys();
602
+ foreach($ids as $id) {
603
+ $snippet=$this->get($id);
604
+ if($snippet) {
605
+ $result+=1;
606
+ /*
607
+ if($snippet['codesCount']>0) {
608
+ $result+=intval($snippet['codesCount']);
609
+ } else {
610
+ $result+=1;
611
+ }
612
+ */
613
+ }
614
+ }
615
+ return $result;
616
+ }
617
+ public function getLastId() {
618
+ $result=0;
619
+ $list=$this->keys();
620
+ foreach ($list as $v) {
621
+ $v=intval($v);
622
+ if ($v>$result) {
623
+ $result=$v;
624
+ }
625
+ }
626
+ return $result;
627
+ }
628
+
629
+ public function values() {
630
+ $keys=$this->keys();
631
+ $array=array();
632
+ foreach ($keys as $k) {
633
+ $v=$this->get($k);
634
+ $array[]=$v;
635
+ }
636
+ usort($array, array($this, 'values_Compare'));
637
+
638
+ $result=array();
639
+ foreach($array as $v) {
640
+ $id=$v['id'];
641
+ $result[$id]=$v;
642
+ }
643
+ return $result;
644
+ }
645
+ public function values_Compare($o1, $o2) {
646
+ global $tcmp;
647
+ $v1=$tcmp->Utils->iget($o1, 'order', FALSE);
648
+ $v2=$tcmp->Utils->iget($o2, 'order', FALSE);
649
+ $result=($v1-$v2);
650
+ if($result==0) {
651
+ $v1=$tcmp->Utils->get($o1, 'name', FALSE);
652
+ $v2=$tcmp->Utils->get($o2, 'name', FALSE);
653
+ $result=strcasecmp($v1, $v2);
654
+ }
655
+ return $result;
656
+ }
657
+ }
includes/classes/core/Singleton.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class TCMP_Singleton {
3
+ var $Lang;
4
+ var $Utils;
5
+ var $Form;
6
+ var $Check;
7
+ var $Options;
8
+ var $Log;
9
+ var $Cron;
10
+ var $Tracking;
11
+ var $Manager;
12
+ var $Ecommerce;
13
+ var $Plugin;
14
+ var $Tabs;
15
+
16
+ function __construct() {
17
+ $this->Lang=new TCMP_Language();
18
+ $this->Tabs=new TCMP_Tabs();
19
+ $this->Utils=new TCMP_Utils();
20
+ $this->Form=new TCMP_Form();
21
+ $this->Check=new TCMP_Check();
22
+ $this->Options=new TCMP_Options();
23
+ $this->Log=new TCMP_Logger();
24
+ $this->Cron=new TCMP_Cron();
25
+ $this->Tracking=new TCMP_Tracking();
26
+ $this->Manager=new TCMP_Manager();
27
+ $this->Ecommerce=new TCMP_Ecommerce();
28
+ $this->Plugin=new TCMP_Plugin();
29
+ }
30
+ public function init() {
31
+ $this->Lang->load('tcmp', TCMP_PLUGIN_DIR.'languages/Lang.txt');
32
+ $this->Tabs->init();
33
+ $this->Cron->init();
34
+ $this->Manager->init();
35
+ }
36
+ }
includes/classes/domain/EcommercePurchase.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+ class TCMP_EcommercePurchase {
4
+ var $orderId;
5
+ var $currency;
6
+
7
+ var $userId;
8
+ var $fullname;
9
+ var $email;
10
+
11
+ var $products=array();
12
+
13
+ var $amount;
14
+ var $total;
15
+ var $tax;
16
+ }
includes/{class-TCM-check.php → classes/ui/Check.php} RENAMED
@@ -1,13 +1,8 @@
1
  <?php
2
- /**
3
- * Created by PhpStorm.
4
- * User: alessio
5
- * Date: 28/03/2015
6
- * Time: 10:20
7
- */
8
  if ( ! defined( 'ABSPATH' ) ) exit;
9
 
10
- class TCM_Check {
11
  var $data;
12
 
13
  public function __construct() {
@@ -41,14 +36,14 @@ class TCM_Check {
41
 
42
  //check if is a mandatory field by checking the .txt language file
43
  private function error($name) {
44
- global $tcm;
45
 
46
  $result=FALSE;
47
- $k=$tcm->Form->prefix.'.'.$name.'.check';
48
- $v=$tcm->Lang->L($k);
49
  if($v!=$k) {
50
  //this is a mandatory field so we give error
51
- $tcm->Options->pushErrorMessage($v);
52
  $result=TRUE;
53
  }
54
  return $result;
@@ -106,7 +101,7 @@ class TCM_Check {
106
  }
107
 
108
  public function hasErrors() {
109
- global $tcm;
110
- return $tcm->Options->hasErrorMessages();
111
  }
112
  }
1
  <?php
2
+
 
 
 
 
 
3
  if ( ! defined( 'ABSPATH' ) ) exit;
4
 
5
+ class TCMP_Check {
6
  var $data;
7
 
8
  public function __construct() {
36
 
37
  //check if is a mandatory field by checking the .txt language file
38
  private function error($name) {
39
+ global $tcmp;
40
 
41
  $result=FALSE;
42
+ $k=$tcmp->Form->prefix.'.'.$name.'.check';
43
+ $v=$tcmp->Lang->L($k);
44
  if($v!=$k) {
45
  //this is a mandatory field so we give error
46
+ $tcmp->Options->pushErrorMessage($v);
47
  $result=TRUE;
48
  }
49
  return $result;
101
  }
102
 
103
  public function hasErrors() {
104
+ global $tcmp;
105
+ return $tcmp->Options->hasErrorMessages();
106
  }
107
  }
includes/classes/ui/Form.php ADDED
@@ -0,0 +1,486 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! defined( 'ABSPATH' ) ) exit;
4
+
5
+ class TCMP_Form {
6
+ var $prefix='Form';
7
+ var $labels=TRUE;
8
+ var $leftLabels=TRUE;
9
+ var $newline;
10
+
11
+ var $tags=TRUE;
12
+ var $onlyPremium=TRUE;
13
+ var $leftTags=FALSE;
14
+ var $premium=FALSE;
15
+ var $tagNew=FALSE;
16
+
17
+ public function __construct() {
18
+ }
19
+
20
+ //args can be a string or an associative array if you want
21
+ private function getTextArgs($args, $defaults, $excludes=array()) {
22
+ $result=$args;
23
+ if(is_array($result) && count($result)>0) {
24
+ $result='';
25
+ foreach($args as $k=>$v) {
26
+ if(count($excludes)==0 || !in_array($k, $excludes)) {
27
+ $result.=' '.$k.'="'.$v.'"';
28
+ }
29
+ }
30
+ } elseif(!$args) {
31
+ $result='';
32
+ }
33
+ if(is_array($defaults) && count($defaults)>0) {
34
+ foreach($defaults as $k=>$v) {
35
+ if(count($excludes)==0 || !in_array($k, $excludes)) {
36
+ if(stripos($result, $k.'=')===FALSE) {
37
+ $result.=' '.$k.'="'.$v.'"';
38
+ }
39
+ }
40
+ }
41
+ }
42
+ return $result;
43
+ }
44
+
45
+ public function tag($overridePremium=FALSE) {
46
+ global $tcmp;
47
+ /*
48
+ $premium=($overridePremium || $this->premium);
49
+ if((!$overridePremium && !$this->tags) || $tcmp->License->hasPremium() || ($this->onlyPremium && !$premium)) return;
50
+
51
+ $tagClass='tcmp-tag-free';
52
+ $tagText='FREE';
53
+ if($premium) {
54
+ $tagClass='tcmp-tag-premium';
55
+ $tagText='<a href="'.TCMP_PAGE_PREMIUM.'" target="_new">PRO</a>';
56
+ }
57
+ */
58
+ if(!$this->tags || !$this->tagNew) {
59
+ return;
60
+ }
61
+
62
+ $tagClass='tcmp-tag-free';
63
+ $tagText='NEW!';
64
+ ?>
65
+ <div style="float:left;" class="tcmp-tag <?php echo $tagClass?>"><?php echo $tagText?></div>
66
+ <?php
67
+ }
68
+
69
+ public function label($name, $options='') {
70
+ global $tcmp;
71
+ $defaults=array('class'=>'');
72
+ $otherText=$this->getTextArgs($options, $defaults, array('label', 'id'));
73
+
74
+ $k=$this->prefix.'.'.$name;
75
+ if(!is_array($options)) {
76
+ $options=array();
77
+ }
78
+ if(isset($options['label']) && $options['label']) {
79
+ $k=$options['label'];
80
+ }
81
+
82
+ $label=$tcmp->Lang->L($k);
83
+ $for=(isset($options['id']) ? $options['id'] : $name);
84
+
85
+ //check if is a mandatory field by checking the .txt language file
86
+ $k=$this->prefix.'.'.$name.'.check';
87
+ if($tcmp->Lang->H($k)) {
88
+ $label.=' (*)';
89
+ }
90
+
91
+ $aClass='';
92
+ /*
93
+ if($this->premium && !$tcmp->License->hasPremium()) {
94
+ $aClass='tcmp-label-disabled';
95
+ }
96
+ */
97
+ ?>
98
+ <label for="<?php echo $for?>" <?php echo $otherText?> >
99
+ <?php if($this->leftTags) {
100
+ $this->tag();
101
+ }?>
102
+ <span style="float:left; margin-right:5px;" class="<?php echo $aClass?>"><?php echo $label?></span>
103
+ <?php if(!$this->leftTags) {
104
+ $this->tag();
105
+ }?>
106
+ </label>
107
+ <?php }
108
+
109
+ public function leftInput($name, $options='') {
110
+ if(!$this->labels) return;
111
+ if($this->leftLabels) {
112
+ $this->label($name, $options);
113
+ }
114
+
115
+ if($this->newline) {
116
+ $this->newline();
117
+ }
118
+ }
119
+
120
+ public function newline() {
121
+ ?><div class="tcmp-form-newline"></div><?php
122
+ }
123
+
124
+ public function rightInput($name, $args='') {
125
+ if(!$this->labels) return;
126
+ if (!$this->leftLabels) {
127
+ $this->label($name, $args);
128
+ }
129
+ $this->newline();
130
+ }
131
+
132
+ public function formStarts($method='post', $action='', $args=NULL) {
133
+ //$this->tags=FALSE;
134
+ //$this->premium=FALSE;
135
+
136
+ //$defaults=array('style'=>'margin:1em 0; padding:1px 1em; background:#fff; border:1px solid #ccc;'
137
+ $defaults=array('class'=>'tcmp-form');
138
+ $other=$this->getTextArgs($args, $defaults);
139
+ ?>
140
+ <form method="<?php echo $method?>" action="<?php echo $action?>" <?php echo $other?> >
141
+ <?php }
142
+
143
+ public function formEnds() { ?>
144
+ </form>
145
+ <?php }
146
+
147
+ public function divStarts($args=array()) {
148
+ $defaults=array();
149
+ $other=$this->getTextArgs($args, $defaults);
150
+ ?>
151
+ <div <?php echo $other?>>
152
+ <?php }
153
+ public function divEnds() { ?>
154
+ </div>
155
+ <div style="clear:both;"></div>
156
+ <?php }
157
+
158
+ public function p($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
159
+ global $tcmp;
160
+ ?>
161
+ <p style="font-weight:bold;">
162
+ <?php
163
+ $tcmp->Lang->P($message, $v1, $v2, $v3, $v4, $v5);
164
+ if($tcmp->Lang->H($message.'Subtitle')) { ?>
165
+ <br/>
166
+ <span style="font-weight:normal;">
167
+ <?php $tcmp->Lang->P($message.'Subtitle', $v1, $v2, $v3, $v4, $v5)?>
168
+ </span>
169
+ <?php } ?>
170
+ </p>
171
+ <?php }
172
+ public function i($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
173
+ global $tcmp;
174
+ ?>
175
+ <i><?php $tcmp->Lang->P($message, $v1, $v2, $v3, $v4, $v5);?></i>
176
+ <?php }
177
+
178
+ var $_aceEditorUsed=FALSE;
179
+ public function editor($name, $value='', $options=NULL) {
180
+ global $tcmp;
181
+
182
+ $defaults=array(
183
+ 'editor'=>'html'
184
+ , 'theme'=>'monokai'
185
+ , 'ui-visible'=>''
186
+ , 'height'=>350
187
+ , 'width'=>700
188
+ );
189
+ $options=$tcmp->Utils->parseArgs($options, $defaults);
190
+ $value=$tcmp->Utils->get($value, $name , $value);
191
+
192
+ $args=array('class'=>'tcmp-label', 'style'=>'width:auto;');
193
+ $this->newline=TRUE;
194
+ $this->leftInput($name, $args);
195
+
196
+ $id=$name;
197
+ switch ($options['editor']) {
198
+ case 'wp':
199
+ case 'wordpress':
200
+ $settings=array(
201
+ 'wpautop'=>TRUE
202
+ , 'media_buttons'=>TRUE
203
+ , 'drag_drop_upload'=>FALSE
204
+ , 'editor_height'=>$options['height']
205
+ );
206
+ wp_editor($value, $id, $settings);
207
+ ?>
208
+ <script>
209
+ jQuery('#<?php echo $id?>').attr('ui-visible', '<?php echo $options['ui-visible']?>');
210
+ </script>
211
+ <?php
212
+ break;
213
+ case 'html':
214
+ case 'text':
215
+ case 'javascript':
216
+ case 'css':
217
+ if(!$this->_aceEditorUsed) { ?>
218
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.3/ace.js" type="text/javascript" charset="utf-8"></script>
219
+ <?php $this->_aceEditorUsed=TRUE;
220
+ }
221
+
222
+ $ace='ACE_'.$id;
223
+ $text=$value;
224
+ //$text=str_replace('&amp;', '&', $text);
225
+ $text=str_replace('<', '&lt;', $text);
226
+ $text=str_replace('>', '&gt;', $text);
227
+ ?>
228
+ <div id="<?php echo $id?>Ace" style="height:<?php echo $options['height']+50?>px; width: <?php echo $options['width']?>px;"><?php echo $text?></div>
229
+ <textarea id="<?php echo $id?>" name="<?php echo $id?>" ui-visible="<?php echo $options['ui-visible']?>" style="display: none;"></textarea>
230
+ <script>
231
+ jQuery.noConflict()(function($){
232
+ var text=$('#<?php echo $id?>Ace').html();
233
+ text=TCMP.replace(text, '&lt;', '<');
234
+ text=TCMP.replace(text, '&gt;', '>');
235
+ text=TCMP.replace(text, '&amp;', '&');
236
+
237
+ var <?php echo $ace?>=ace.edit("<?php echo $id?>Ace");
238
+ <?php echo $ace?>.renderer.setShowGutter(false);
239
+ <?php echo $ace?>.setTheme("ace/theme/<?php echo $options['theme']?>");
240
+ <?php echo $ace?>.getSession().setMode("ace/mode/<?php echo $options['editor']?>");
241
+ <?php echo $ace?>.getSession().setUseSoftTabs(true);
242
+ <?php echo $ace?>.getSession().setUseWrapMode(true);
243
+ <?php echo $ace?>.session.setUseWorker(false)
244
+ <?php echo $ace?>.setValue(text);
245
+
246
+ $('#<?php echo $id?>Ace').focusout(function() {
247
+ var $hidden=$('#<?php echo $id?>');
248
+ var code=<?php echo $ace?>.getValue();
249
+ $hidden.val(code);
250
+ });
251
+ $('#<?php echo $id?>Ace').trigger('focusout');
252
+ });
253
+ </script>
254
+ <?php
255
+ break;
256
+ }
257
+ $this->newline=FALSE;
258
+ $this->rightInput($name, $args);
259
+ }
260
+
261
+ public function textarea($name, $value='', $args=NULL) {
262
+ if(is_array($value) && isset($value[$name])) {
263
+ $value=$value[$name];
264
+ }
265
+ $defaults=array('rows'=>10, 'class'=>'tcmp-textarea');
266
+ $other=$this->getTextArgs($args, $defaults);
267
+
268
+ $args=array('class'=>'tcmp-label', 'style'=>'width:auto;');
269
+ $this->newline=TRUE;
270
+ $this->leftInput($name, $args);
271
+ ?>
272
+ <textarea dir="ltr" dirname="ltr" id="<?php echo $name ?>" name="<?php echo $name?>" <?php echo $other?> ><?php echo $value ?></textarea>
273
+ <?php
274
+ $this->newline=FALSE;
275
+ $this->rightInput($name, $args);
276
+ }
277
+
278
+ public function text($name, $value='', $options=NULL) {
279
+ if(is_array($value) && isset($value[$name])) {
280
+ $value=$value[$name];
281
+ }
282
+ $defaults=array('class'=>'tcmp-text');
283
+ $other=$this->getTextArgs($options, $defaults);
284
+
285
+ $options=array('class'=>'tcmp-label');
286
+ $this->leftInput($name, $options);
287
+ ?>
288
+ <input type="text" id="<?php echo $name ?>" name="<?php echo $name ?>" value="<?php echo $value ?>" <?php echo $other?> />
289
+ <?php
290
+ $this->rightInput($name, $options);
291
+ }
292
+
293
+ public function hidden($name, $value='', $args=NULL) {
294
+ if(is_array($value) && isset($value[$name])) {
295
+ $value=$value[$name];
296
+ }
297
+ $defaults=array();
298
+ $other=$this->getTextArgs($args, $defaults);
299
+ ?>
300
+ <input type="hidden" id="<?php echo $name ?>" name="<?php echo $name ?>" value="<?php echo $value ?>" <?php echo $other?> />
301
+ <?php }
302
+
303
+ public function nonce($action=-1, $name='_wpnonce', $referer=true, $echo=true) {
304
+ wp_nonce_field($action, $name, $referer, $echo);
305
+ }
306
+
307
+ public function dropdown($name, $value, $options, $multiple=FALSE, $args=NULL) {
308
+ global $tcmp;
309
+ if(is_array($value) && isset($value[$name])) {
310
+ $value=$value[$name];
311
+ }
312
+ $defaults=array('class'=>'tcmp-select tcmTags tcmp-dropdown');
313
+ $other=$this->getTextArgs($args, $defaults);
314
+
315
+ if(!is_array($value)) {
316
+ $value=array($value);
317
+ }
318
+ if(is_string($options)) {
319
+ $options=explode(',', $options);
320
+ }
321
+ if(is_array($options) && count($options)>0) {
322
+ if(!isset($options[0]['id'])) {
323
+ //this is a normal array so I use the values for "id" field and the "name" into the txt file
324
+ $temp=array();
325
+ foreach($options as $v) {
326
+ $temp[]=array('id'=>$v, 'name'=>$tcmp->Lang->L($this->prefix.'.'.$name.'.'.$v));
327
+ }
328
+ $options=$temp;
329
+ }
330
+ }
331
+
332
+ echo "<div id=\"$name-box\">";
333
+ $args=array('class'=>'tcmp-label');
334
+ $this->leftInput($name, $args);
335
+ ?>
336
+ <select id="<?php echo $name ?>" name="<?php echo $name?><?php echo ($multiple ? '[]' : '')?>" <?php echo ($multiple ? 'multiple' : '')?> <?php echo $other?> >
337
+ <?php
338
+ foreach($options as $v) {
339
+ $selected='';
340
+ if(in_array($v['id'], $value)) {
341
+ $selected=' selected="selected"';
342
+ }
343
+ ?>
344
+ <option value="<?php echo $v['id']?>" <?php echo $selected?>><?php echo $v['name']?></option>
345
+ <?php } ?>
346
+ </select>
347
+ <?php
348
+ $this->rightInput($name, $args);
349
+ echo '</div>';
350
+ }
351
+
352
+ public function br() { ?>
353
+ <br/>
354
+ <?php }
355
+
356
+ public function submit($value='', $args=NULL) {
357
+ global $tcmp;
358
+ $defaults=array();
359
+ $other=$this->getTextArgs($args, $defaults);
360
+ if($value=='') {
361
+ $value='Send';
362
+ }
363
+ $this->newline();
364
+ ?>
365
+ <input type="submit" class="button-primary tcmp-button tcmp-submit" value="<?php $tcmp->Lang->P($value)?>" <?php echo $other?>/>
366
+ <?php }
367
+
368
+ public function delete($id, $action='delete', $args=NULL) {
369
+ global $tcmp;
370
+ $defaults=array();
371
+ $other=$this->getTextArgs($args, $defaults);
372
+ ?>
373
+ <input type="button" class="button tcmp-button" value="<?php $tcmp->Lang->P('Delete?')?>" onclick="if (confirm('<?php $tcmp->Lang->P('Question.DeleteQuestion')?>') ) window.location='<?php echo TCMP_TAB_MANAGER_URI?>&action=<?php echo $action?>&id=<?php echo $id ?>&amp;tcmp_nonce=<?php echo esc_attr(wp_create_nonce('tcmp_delete')); ?>';" <?php echo $other?> />
374
+ &nbsp;
375
+ <?php
376
+ }
377
+
378
+ public function radio($name, $current=1, $value=1, $options=NULL) {
379
+ if(!is_array($options)) {
380
+ $options=array();
381
+ }
382
+ $options['radio']=TRUE;
383
+ $options['id']=$name.'_'.$value;
384
+ return $this->checkbox($name, $current, $value, $options);
385
+ }
386
+ public function checkbox($name, $current=1, $value=1, $options=NULL) {
387
+ global $tcmp;
388
+ if(is_array($current) && isset($current[$name])) {
389
+ $current=$current[$name];
390
+ }
391
+
392
+ /*
393
+ $defaults=array('class'=>'tcmp-checkbox', 'style'=>'margin:0px; margin-right:4px;');
394
+ if($this->premium && !$tcmp->License->hasPremium()) {
395
+ $defaults['disabled']='disabled';
396
+ $value='';
397
+ }
398
+ */
399
+ if(!is_array($options)) {
400
+ $options=array();
401
+ }
402
+
403
+ $label=$name;
404
+ $type='checkbox';
405
+ if(isset($options['radio']) && $options['radio']) {
406
+ $type='radio';
407
+ $label.='_'.$value;
408
+ }
409
+
410
+ $defaults=array(
411
+ 'class'=>'tcmp-checkbox'
412
+ , 'style'=>'margin:0px; margin-right:4px;'
413
+ , 'id'=>$name
414
+ );
415
+ $other=$this->getTextArgs($options, $defaults, array('radio', 'label'));
416
+ $prev=$this->leftLabels;
417
+ $this->leftLabels=FALSE;
418
+
419
+ $label=(isset($options['label']) ? $options['label'] : $this->prefix.'.'.$label);
420
+ $id=(isset($options['id']) ? $options['id'] : $name);
421
+ $options=array(
422
+ 'class'=>''
423
+ , 'style'=>'margin-top:-1px;'
424
+ , 'label'=>$label
425
+ , 'id'=>$id
426
+ );
427
+ $this->leftInput($name, $options);
428
+ ?>
429
+ <input type="<?php echo $type ?>" name="<?php echo $name?>" value="<?php echo $value?>" <?php echo($current==$value ? 'checked="checked"' : '') ?> <?php echo $other?> >
430
+ <?php
431
+ $this->rightInput($name, $options);
432
+ $this->leftLabels=$prev;
433
+ }
434
+
435
+ public function checkText($nameActive, $nameText, $value) {
436
+ global $tcmp;
437
+
438
+ $args=array('class'=>'tcmp-hideShow tcmp-checkbox'
439
+ , 'tcmp-hideIfTrue'=>'false'
440
+ , 'tcmp-hideShow'=>$nameText.'Text');
441
+ $this->checkbox($nameActive, $value, 1, $args);
442
+ if($this->premium) {
443
+ return;
444
+ }
445
+ ?>
446
+ <div id="<?php echo $nameText?>Text" style="float:left;">
447
+ <?php
448
+ $prev=$this->labels;
449
+ $this->labels=FALSE;
450
+ $args=array();
451
+ $this->text($nameText, $value, $args);
452
+ $this->labels=$prev;
453
+ ?>
454
+ </div>
455
+ <?php }
456
+
457
+ //create a checkbox with a left select visible only when the checkbox is selected
458
+ public function checkSelect($nameActive, $nameArray, $value, $values, $options=NULL) {
459
+ global $tcmp;
460
+ ?>
461
+ <div id="<?php echo $nameArray?>Box" style="float:left;">
462
+ <?php
463
+ $defaults=array(
464
+ 'class'=>'tcmp-hideShow tcmp-checkbox'
465
+ , 'tcmp-hideIfTrue'=>'false'
466
+ , 'tcmp-hideShow'=>$nameArray.'Tags'
467
+ );
468
+ $options=$tcmp->Utils->parseArgs($options, $defaults);
469
+ $this->checkbox($nameActive, $value, 1, $options);
470
+ /*if(!$this->premium || $tcmp->License->hasPremium()) { ?>*/
471
+ if(TRUE) { ?>
472
+ <div id="<?php echo $nameArray?>Tags" style="float:left;">
473
+ <?php
474
+ $prev=$this->labels;
475
+ $this->labels=FALSE;
476
+ $options=array('class'=>'tcmp-select tcmLineTags');
477
+ $this->dropdown($nameArray, $value, $values, TRUE, $options);
478
+ $this->labels=$prev;
479
+ ?>
480
+ </div>
481
+ <?php } ?>
482
+ </div>
483
+ <?php
484
+ $this->newline();
485
+ }
486
+ }
includes/classes/ui/Tabs.php ADDED
@@ -0,0 +1,294 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class TCMP_Tabs {
3
+ private $tabs = array();
4
+
5
+ function __construct() {
6
+ }
7
+ public function init() {
8
+ global $tcmp;
9
+ if($tcmp->Utils->isAdminUser()) {
10
+ add_action('admin_menu', array(&$this, 'attachMenu'));
11
+ add_filter('plugin_action_links', array(&$this, 'pluginActions'), 10, 2);
12
+ if($tcmp->Utils->isPluginPage()) {
13
+ add_action('admin_enqueue_scripts', array(&$this, 'enqueueScripts'));
14
+ }
15
+ }
16
+ }
17
+
18
+ function attachMenu() {
19
+ add_submenu_page('options-general.php'
20
+ , TCMP_PLUGIN_NAME, TCMP_PLUGIN_NAME
21
+ , 'manage_options', TCMP_PLUGIN_SLUG, array(&$this, 'showTabPage'));
22
+ }
23
+ function pluginActions($links, $file) {
24
+ global $tcmp;
25
+ if($file==TCMP_PLUGIN_SLUG.'/index.php'){
26
+ $settings=array();
27
+ $settings[]="<a href='".TCMP_TAB_MANAGER_URI."'>".$tcmp->Lang->L('Settings').'</a>';
28
+ $settings[]="<a href='".TCMP_PAGE_PREMIUM."'>".$tcmp->Lang->L('PREMIUM').'</a>';
29
+ $links=array_merge($settings, $links);
30
+ }
31
+ return $links;
32
+ }
33
+ function enqueueScripts() {
34
+ wp_enqueue_script('jquery');
35
+ wp_enqueue_script('jQuery');
36
+ wp_enqueue_script('jquery-ui-sortable');
37
+
38
+ $this->wpEnqueueStyle('assets/css/style.css');
39
+ $this->wpEnqueueStyle('assets/deps/select2-3.5.2/select2.css');
40
+ $this->wpEnqueueScript('assets/deps/select2-3.5.2/select2.min.js');
41
+ $this->wpEnqueueScript('assets/deps/starrr/starrr.js');
42
+
43
+ $this->wpEnqueueScript('assets/js/library.js');
44
+ $this->wpEnqueueScript('assets/js/plugin.js');
45
+ }
46
+ function wpEnqueueStyle($uri, $name='') {
47
+ if($name=='') {
48
+ $name=explode('/', $uri);
49
+ $name=$name[count($name)-1];
50
+ $dot=strrpos($name, '.');
51
+ if($dot!==FALSE) {
52
+ $name=substr($name, 0, $dot);
53
+ }
54
+ $name=TCMP_PLUGIN_PREFIX.'_'.$name;
55
+ }
56
+
57
+ $v='?v='.TCMP_PLUGIN_VERSION;
58
+ wp_enqueue_style($name, TCMP_PLUGIN_URI.$uri.$v);
59
+ }
60
+ function wpEnqueueScript($uri, $name='', $version=FALSE) {
61
+ if($name=='') {
62
+ $name=explode('/', $uri);
63
+ $name=$name[count($name)-1];
64
+ $dot=strrpos($name, '.');
65
+ if($dot!==FALSE) {
66
+ $name=substr($name, 0, $dot);
67
+ }
68
+ $name=TCMP_PLUGIN_PREFIX.'_'.$name;
69
+ }
70
+
71
+ $v='?v='.TCMP_PLUGIN_VERSION;
72
+ $deps=array();
73
+ wp_enqueue_script($name, TCMP_PLUGIN_URI.$uri.$v, $deps, $version, FALSE);
74
+ }
75
+
76
+ function showTabPage() {
77
+ global $tcmp;
78
+
79
+ $v=$tcmp->Options->getShowWhatsNewSeenVersion();
80
+ if($v!=TCMP_WHATSNEW_VERSION) {
81
+ $tcmp->Options->setShowWhatsNew(TRUE);
82
+ }
83
+
84
+ $hwb=TCMP_ISQS('hwb', '');
85
+ if($hwb!='') {
86
+ $tcmp->Options->setShowWhatsNew(FALSE);
87
+ }
88
+
89
+ $id=TCMP_ISQS('id', 0);
90
+ $defaultTab=TCMP_TAB_MANAGER;
91
+ $tab=TCMP_SQS('tab', $defaultTab);
92
+
93
+ if($tcmp->Options->isShowWhatsNew()) {
94
+ $tab=TCMP_TAB_WHATS_NEW;
95
+ $defaultTab=$tab;
96
+ $this->tabs[TCMP_TAB_WHATS_NEW]=$tcmp->Lang->L('What\'s New');
97
+ //$this->tabs[TCMP_TAB_MANAGER]=$tcmp->Lang->L('Start using the plugin!');
98
+ } else {
99
+ if($id>0 || !$tcmp->Manager->isLimitReached(FALSE)) {
100
+ $this->tabs[TCMP_TAB_EDITOR]=$tcmp->Lang->L($id>0 && $tab==TCMP_TAB_EDITOR ? 'Edit Script' : 'Add New Script');
101
+ } elseif($tab==TCMP_TAB_EDITOR) {
102
+ $tab = TCMP_TAB_MANAGER;
103
+ }
104
+
105
+ $this->tabs[TCMP_TAB_MANAGER]=$tcmp->Lang->L('Manager');
106
+ $this->tabs[TCMP_TAB_SETTINGS]=$tcmp->Lang->L('Settings');
107
+ $this->tabs[TCMP_TAB_DOCS]=$tcmp->Lang->L('Docs & FAQ');
108
+ }
109
+
110
+ ?>
111
+
112
+ <div class="wrap" style="margin: 5px;">
113
+ <?php
114
+ $this->showTabs($defaultTab);
115
+ $header='';
116
+ switch ($tab) {
117
+ case TCMP_TAB_EDITOR:
118
+ $header=($id>0 ? 'Edit' : 'Add');
119
+ break;
120
+ case TCMP_TAB_WHATS_NEW:
121
+ $header='';
122
+ break;
123
+ case TCMP_TAB_MANAGER:
124
+ $header='Manager';
125
+ break;
126
+ case TCMP_TAB_SETTINGS:
127
+ $header='Settings';
128
+ break;
129
+ }
130
+
131
+ if($tcmp->Lang->H($header.'Title')) { ?>
132
+ <h2><?php $tcmp->Lang->P($header . 'Title', TCMP_PLUGIN_VERSION) ?></h2>
133
+ <?php if ($tcmp->Lang->H($header . 'Subtitle')) { ?>
134
+ <div><?php $tcmp->Lang->P($header . 'Subtitle') ?></div>
135
+ <?php } ?>
136
+ <br/>
137
+ <?php }
138
+
139
+ tcmp_ui_first_time();
140
+ ?>
141
+ <div style="float:left; margin:5px;">
142
+ <?php
143
+ $styles=array();
144
+ $styles[]='float:left';
145
+ $styles[]='margin-right:20px';
146
+ if($tab!=TCMP_TAB_WHATS_NEW) {
147
+ $styles[]='max-width:750px';
148
+ }
149
+ $styles=implode('; ', $styles);
150
+ ?>
151
+ <div id="tcmp-page" style="<?php echo $styles?>">
152
+ <?php switch ($tab) {
153
+ case TCMP_TAB_WHATS_NEW:
154
+ tcmp_ui_whats_new();
155
+ break;
156
+ case TCMP_TAB_EDITOR:
157
+ tcmp_ui_editor();
158
+ break;
159
+ case TCMP_TAB_MANAGER:
160
+ tcmp_ui_manager();
161
+ break;
162
+ case TCMP_TAB_SETTINGS:
163
+ tcmp_ui_track();
164
+ tcmp_ui_settings();
165
+ break;
166
+ } ?>
167
+ </div>
168
+ <?php if($tab!=TCMP_TAB_WHATS_NEW) { ?>
169
+ <div id="tcmp-sidebar" style="float:left; max-width: 250px;">
170
+ <?php
171
+ $count=$this->getPluginsCount();
172
+ $plugins=array();
173
+ while(count($plugins)<2) {
174
+ $id=rand(1, $count);
175
+ if(!isset($plugins[$id])) {
176
+ $plugins[$id]=$id;
177
+ }
178
+ }
179
+
180
+ $this->drawContactUsWidget();
181
+ foreach($plugins as $id) {
182
+ $this->drawPluginWidget($id);
183
+ }
184
+ ?>
185
+ </div>
186
+ <?php } ?>
187
+ </div>
188
+ </div>
189
+ <div style="clear:both"></div>
190
+ <?php }
191
+ function getPluginsCount() {
192
+ global $tcmp;
193
+ $index=1;
194
+ while($tcmp->Lang->H('Plugin'.$index.'.Name')) {
195
+ $index++;
196
+ }
197
+ return $index-1;
198
+ }
199
+ function drawPluginWidget($id) {
200
+ global $tcmp;
201
+ ?>
202
+ <div class="tcmp-plugin-widget">
203
+ <b><?php $tcmp->Lang->P('Plugin'.$id.'.Name') ?></b>
204
+ <br>
205
+ <i><?php $tcmp->Lang->P('Plugin'.$id.'.Subtitle') ?></i>
206
+ <br>
207
+ <ul style="list-style: circle;">
208
+ <?php
209
+ $index=1;
210
+ while($tcmp->Lang->H('Plugin'.$id.'.Feature'.$index)) { ?>
211
+ <li><?php $tcmp->Lang->P('Plugin'.$id.'.Feature'.$index) ?></li>
212
+ <?php $index++;
213
+ } ?>
214
+ </ul>
215
+ <a style="float:right;" class="button-primary" href="<?php $tcmp->Lang->P('Plugin'.$id.'.Permalink') ?>" target="_blank">
216
+ <?php $tcmp->Lang->P('PluginCTA')?>
217
+ </a>
218
+ <div style="clear:both"></div>
219
+ </div>
220
+ <br>
221
+ <?php }
222
+ function drawContactUsWidget() {
223
+ global $tcmp;
224
+ ?>
225
+ <b><?php $tcmp->Lang->P('Sidebar.Title') ?></b>
226
+ <ul style="list-style: circle;">
227
+ <?php
228
+ $index=1;
229
+ while($tcmp->Lang->H('Sidebar'.$index.'.Name')) { ?>
230
+ <li>
231
+ <a href="<?php $tcmp->Lang->P('Sidebar'.$index.'.Url')?>" target="_blank">
232
+ <?php $tcmp->Lang->P('Sidebar'.$index.'.Name')?>
233
+ </a>
234
+ </li>
235
+ <?php $index++;
236
+ } ?>
237
+ </ul>
238
+ <?php }
239
+ function showTabs($defaultTab) {
240
+ global $tcmp;
241
+ $tab=$tcmp->Check->of('tab', $defaultTab);
242
+ if($tab==TCMP_TAB_DOCS) {
243
+ $tcmp->Utils->redirect(TCMP_TAB_DOCS_URI);
244
+ }
245
+ if($tcmp->Options->isShowWhatsNew()) {
246
+ $tab=TCMP_TAB_WHATS_NEW;
247
+ }
248
+
249
+ ?>
250
+ <h2 class="nav-tab-wrapper" style="float:left; width:97%;">
251
+ <?php
252
+ foreach ($this->tabs as $k=>$v) {
253
+ $active = ($tab==$k ? 'nav-tab-active' : '');
254
+ $style='';
255
+ $target='_self';
256
+ if($tcmp->Options->isShowWhatsNew() && $k==TCMP_TAB_MANAGER) {
257
+ $active='';
258
+ $style='background-color:#F2E49B';
259
+ }
260
+ if($k==TCMP_TAB_DOCS) {
261
+ $target='_blank';
262
+ $style='background-color:#F2E49B';
263
+ }
264
+ ?>
265
+ <a style="float:left; margin-left:10px; <?php echo $style?>" class="nav-tab <?php echo $active?>" target="<?php echo $target ?>" href="?page=<?php echo TCMP_PLUGIN_SLUG?>&tab=<?php echo $k?>"><?php echo $v?></a>
266
+ <?php
267
+ }
268
+ ?>
269
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.min.css">
270
+ <style>
271
+ .starrr {display:inline-block}
272
+ .starrr i{font-size:16px;padding:0 1px;cursor:pointer;color:#2ea2cc;}
273
+ </style>
274
+ <div style="float:right; display:none;" id="rate-box">
275
+ <span style="font-weight:700; font-size:13px; color:#555;"><?php $tcmp->Lang->P('Rate us')?></span>
276
+ <div id="tcmp-rate" class="starrr" data-connected-input="tcmp-rate-rank"></div>
277
+ <input type="hidden" id="tcmp-rate-rank" name="tcmp-rate-rank" value="5" />
278
+ <?php $tcmp->Utils->twitter('intellywp') ?>
279
+ </div>
280
+ <script>
281
+ jQuery(function() {
282
+ jQuery(".starrr").starrr();
283
+ jQuery('#tcmp-rate').on('starrr:change', function(e, value){
284
+ var url='https://wordpress.org/support/view/plugin-reviews/tracking-code-manager?rate=5#postform';
285
+ window.open(url);
286
+ });
287
+ jQuery('#rate-box').show();
288
+ });
289
+ </script>
290
+ </h2>
291
+ <div style="clear:both;"></div>
292
+ <?php }
293
+ }
294
+
includes/classes/utils/Cron.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) exit;
3
+
4
+ class TCMP_Cron {
5
+ public function __construct() {
6
+
7
+ }
8
+ public function init() {
9
+ add_filter( 'cron_schedules', array( $this, 'add_schedules' ) );
10
+ add_action( 'wp', array( $this, 'schedule_Events' ) );
11
+ }
12
+ public function add_schedules( $schedules = array() ) {
13
+ global $tcmp;
14
+ // Adds once weekly to the existing schedules.
15
+ $schedules['weekly'] = array(
16
+ 'interval' => 604800,
17
+ 'display' => $tcmp->Lang->L('Once Weekly')
18
+ );
19
+
20
+ return $schedules;
21
+ }
22
+ public function schedule_Events() {
23
+ $this->weekly_events();
24
+ $this->daily_events();
25
+ }
26
+ private function weekly_events() {
27
+ if ( ! wp_next_scheduled( 'tcmp_weekly_scheduled_events' ) ) {
28
+ wp_schedule_event( current_time( 'timestamp' ), 'weekly', 'tcmp_weekly_scheduled_events' );
29
+ }
30
+ }
31
+ private function daily_events() {
32
+ if ( ! wp_next_scheduled( 'tcmp_daily_scheduled_events' ) ) {
33
+ wp_schedule_event( current_time( 'timestamp' ), 'daily', 'tcmp_daily_scheduled_events' );
34
+ }
35
+ }
36
+ }
includes/classes/utils/Ecommerce.php ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ class TCMP_Ecommerce {
5
+ var $_orderId;
6
+
7
+ function __construct() {
8
+ add_action('woocommerce_thankyou', array(&$this, 'wooCommerceThankYou'), -10);
9
+ //add_action('woocommerce_thankyou_order_id', array(&$this, 'wooCommerceThankYou'), -10);
10
+
11
+ add_action('edd_payment_receipt_after_table', array(&$this, 'eddThankYou'));
12
+ add_action('wpsc_transaction_result_cart_item', array(&$this, 'eCommerceThankYou'));
13
+ }
14
+
15
+ public function getCustomPostType($pluginId) {
16
+ $result='';
17
+ switch (intval($pluginId)) {
18
+ case TCMP_PLUGINS_WOOCOMMERCE:
19
+ $result='product';
20
+ break;
21
+ case TCMP_PLUGINS_EDD:
22
+ $result='download';
23
+ break;
24
+ case TCMP_PLUGINS_WP_ECOMMERCE:
25
+ $result='wpsc-product';
26
+ break;
27
+ }
28
+ return $result;
29
+ }
30
+
31
+ //WPSC_Purchase_Log_Customer_HTML_Notification
32
+ function eCommerceThankYou($order) {
33
+ global $tcmp;
34
+ $purchase=new TCMP_EcommercePurchase();
35
+
36
+ $orderId=intval($order['purchase_id']);
37
+ $purchase->orderId=$orderId;
38
+ $tcmp->Log->debug('Ecommerce: ECOMMERCE THANKYOU');
39
+ $tcmp->Log->debug('Ecommerce: NEW ECOMMERCE ORDERID=%s', $orderId);
40
+
41
+ $order=new WPSC_Purchase_Log($orderId);
42
+ $items=$order->get_cart_contents();
43
+ $productsIds=array();
44
+ foreach ($items as $v) {
45
+ if(isset($v->prodid)) {
46
+ $k=intval($v->prodid);
47
+ if($k) {
48
+ $v=$v->name;
49
+ $purchase->products[]=$v;
50
+ $productsIds[]=$k;
51
+ $tcmp->Log->debug('Ecommerce: ITEM %s=%s IN CART', $k, $v);
52
+ }
53
+ }
54
+ }
55
+
56
+ $args=array(
57
+ 'pluginId'=>TCMP_PLUGINS_WP_ECOMMERCE
58
+ , 'productsIds'=>$productsIds
59
+ , 'categoriesIds'=>array()
60
+ , 'tagsIds'=>array()
61
+ );
62
+ $tcmp->Options->pushConversionSnippets($args, $purchase);
63
+ return '';
64
+ }
65
+
66
+ function eddThankYou($payment, $edd_receipt_args=NULL) {
67
+ global $tcmp;
68
+ if(!class_exists('EDD_Customer')) {
69
+ return;
70
+ }
71
+
72
+ /* @var $payment WP_Post */
73
+ $purchase=new TCMP_EcommercePurchase();
74
+ $purchase->orderId=$tcmp->Utils->get($payment, 'ID');
75
+ $purchase->userId=$tcmp->Utils->get($payment, 'post_author', FALSE);
76
+
77
+ $settings=edd_get_settings();
78
+ if(isset($settings['currency'])) {
79
+ $purchase->currency=$settings['currency'];
80
+ }
81
+
82
+ $tcmp->Log->debug('Ecommerce: EDD THANKYOU');
83
+ $tcmp->Log->debug('Ecommerce: NEW EDD ORDERID=%s', $purchase->orderId);
84
+ $cart=edd_get_payment_meta_cart_details($purchase->orderId, TRUE);
85
+ $productsIds=array();
86
+ $purchase->amount=0;
87
+ $purchase->total=0;
88
+ foreach ($cart as $key=>$item) {
89
+ if(isset($item['id'])) {
90
+ $k=intval($item['id']);
91
+ if($k) {
92
+ $v=$item['name'];
93
+ $purchase->products[]=$v;
94
+ $productsIds[]=$k;
95
+ $tcmp->Log->debug('Ecommerce: ITEM %s=%s IN CART', $k, $v);
96
+ }
97
+ }
98
+ }
99
+
100
+ $args=array(
101
+ 'pluginId'=>TCMP_PLUGINS_EDD
102
+ , 'productsIds'=>$productsIds
103
+ , 'categoriesIds'=>array()
104
+ , 'tagsIds'=>array()
105
+ );
106
+ $tcmp->Options->pushConversionSnippets($args, $purchase);
107
+ }
108
+ function wooCommerceThankYou($orderId) {
109
+ global $tcmp;
110
+ if(!$orderId) {
111
+ return;
112
+ }
113
+ if($this->_orderId===$orderId) {
114
+ return;
115
+ }
116
+
117
+ $this->_orderId=$orderId;
118
+ $purchase=new TCMP_EcommercePurchase();
119
+ $purchase->orderId=$orderId;
120
+ $tcmp->Log->debug('Ecommerce: WOOCOMMERCE THANKYOU');
121
+
122
+ $order=new WC_Order($orderId);
123
+ $purchase->email=$order->get_billing_email();
124
+ $purchase->fullname=$order->get_billing_first_name();
125
+ if($order->get_billing_last_name()!='') {
126
+ $purchase->fullname.=' '.$order->get_billing_last_name();
127
+ }
128
+
129
+ $items=$order->get_items();
130
+ $tcmp->Log->debug('Ecommerce: NEW WOOCOMMERCE ORDERID=%s', $orderId);
131
+ $productsIds=array();
132
+ foreach($items as $k=>$v) {
133
+ $k=intval($v['product_id']);
134
+ if($k>0) {
135
+ $v=$v['name'];
136
+ $purchase->products[]=$v;
137
+ $tcmp->Log->debug('Ecommerce: ITEM %s=%s IN CART', $k, $v);
138
+ $productsIds[]=$k;
139
+ }
140
+ }
141
+
142
+ $args=array(
143
+ 'pluginId'=>TCMP_PLUGINS_WOOCOMMERCE
144
+ , 'productsIds'=>$productsIds
145
+ , 'categoriesIds'=>array()
146
+ , 'tagsIds'=>array()
147
+ );
148
+ $tcmp->Options->pushConversionSnippets($args, $purchase);
149
+ }
150
+
151
+ function getActivePlugins() {
152
+ return $this->getPlugins(TRUE);
153
+ }
154
+ function getPlugins($onlyActive=TRUE) {
155
+ global $tcmp;
156
+
157
+ $array=array();
158
+ $array[]=TCMP_PLUGINS_WOOCOMMERCE;
159
+ $array[]=TCMP_PLUGINS_EDD;
160
+ $array[]=TCMP_PLUGINS_WP_ECOMMERCE;
161
+ /*
162
+ $array[]=TCMP_PLUGINS_WP_SPSC;
163
+ $array[]=TCMP_PLUGINS_S2MEMBER;
164
+ $array[]=TCMP_PLUGINS_MEMBERS;
165
+ $array[]=TCMP_PLUGINS_CART66;
166
+ $array[]=TCMP_PLUGINS_ESHOP;
167
+ $array[]=TCMP_PLUGINS_JIGOSHOP;
168
+ $array[]=TCMP_PLUGINS_MARKETPRESS;
169
+ $array[]=TCMP_PLUGINS_SHOPP;
170
+ $array[]=TCMP_PLUGINS_SIMPLE_WP_ECOMMERCE;
171
+ $array[]=TCMP_PLUGINS_CF7;
172
+ $array[]=TCMP_PLUGINS_GRAVITY;
173
+ */
174
+
175
+ $array=$tcmp->Plugin->getPlugins($array, $onlyActive);
176
+ return $array;
177
+ }
178
+ }
includes/classes/utils/Language.php ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ class TCMP_Language {
5
+ var $domain;
6
+ var $bundle;
7
+
8
+ function __construct() {
9
+ $this->bundle=new TCMP_Properties();
10
+ }
11
+ function load($domain, $file) {
12
+ $this->domain=$domain;
13
+ $this->bundle->load($file);
14
+ }
15
+ //echo the $ec->Lang->L result
16
+ function P($key, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
17
+ $what=$this->L($key, $v1, $v2, $v3, $v4, $v5);
18
+ echo $what;
19
+ }
20
+ //verify if the key is defined or not
21
+ function H($key) {
22
+ if($this->bundle==NULL || !$this->bundle->hasKeys()) {
23
+ return FALSE;
24
+ }
25
+
26
+ $result=FALSE;
27
+ if($this->bundle->existsKey($key)) {
28
+ $result=TRUE;
29
+ } elseif($this->bundle->existsKey($key.'1')) {
30
+ $result=TRUE;
31
+ } else {
32
+ //special way to call this function passing arguments
33
+ //WTF_something means key=WTF and something as first argument
34
+ $s=strpos($result, '_');
35
+ if ($s!==FALSE) {
36
+ $text=substr($result, 0, $s);
37
+ $value=substr($result, $s + 1);
38
+ $e=strrpos($value, '_');
39
+ if ($e!==FALSE) {
40
+ $text.=substr($value, $e + 1);
41
+ $value=substr($value, 0, $e);
42
+ }
43
+ if ($this->bundle->existsKey($text)) {
44
+ $result=TRUE;
45
+ }
46
+ }
47
+ }
48
+ return $result;
49
+ }
50
+ //read the key from a text file with its translation. Try to translate using __(
51
+ function L($key, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
52
+ global $tcmp;
53
+ $result=$key;
54
+ $args=array($v1, $v2, $v3, $v4, $v5);
55
+
56
+ if($this->bundle==NULL || !$this->bundle->hasKeys()) {
57
+ $result=__($result, $this->domain);
58
+ } else {
59
+ //i use the file to store the translations without writing it inside the code
60
+ if ($this->bundle->existsKey($key)) {
61
+ $result=$this->bundle->getString($key);
62
+ $result=__($result, $this->domain);
63
+ } elseif ($this->bundle->existsKey($key.'1')) {
64
+ $result='';
65
+ $n=1;
66
+ while ($this->bundle->existsKey($key.$n)) {
67
+ if ($result != '') {
68
+ $result .= '<br/>';
69
+ }
70
+ $result .= __($this->bundle->getString($key . $n), $this->domain);
71
+ ++$n;
72
+ }
73
+ } else {
74
+ //special way to call this function passing arguments
75
+ //WTF_something means key=WTF and something as first argument
76
+ $s=strpos($result, '_');
77
+ if ($s!==FALSE) {
78
+ $text=substr($result, 0, $s);
79
+ $value=substr($result, $s + 1);
80
+ $e=strrpos($value, '_');
81
+ if ($e!==FALSE) {
82
+ $text .= substr($value, $e + 1);
83
+ $value=substr($value, 0, $e);
84
+ }
85
+ if ($this->bundle->existsKey($text)) {
86
+ $result=$this->bundle->getString($text);
87
+ $args=array($value);
88
+ }
89
+ }
90
+ $result=__($result, $this->domain);
91
+ }
92
+ }
93
+ if($result==$key) {
94
+ $this->bundle->pushString($key, '');
95
+ }
96
+ //here i translate it using WP
97
+ foreach($args as $k=>$v) {
98
+ $k='{'.$k.'}';
99
+ while(strpos($result, $k)!==FALSE) {
100
+ $result=str_replace($k, $v, $result);
101
+ }
102
+ }
103
+ foreach($args as $k=>$v) {
104
+ $k='{dt:'.$k.'}';
105
+ $v=$tcmp->Utils->formatSmartDatetime($v);
106
+ while(strpos($result, $k)!==FALSE) {
107
+ $result=str_replace($k, $v, $result);
108
+ }
109
+ }
110
+ return $result;
111
+ }
112
+ }
includes/{class-TCM-logger.php → classes/utils/Logger.php} RENAMED
@@ -1,19 +1,15 @@
1
  <?php
2
- /**
3
- * Created by PhpStorm.
4
- * User: alessio
5
- * Date: 24/03/2015
6
- * Time: 08:45
7
- */
8
  // Exit if accessed directly
9
  if ( ! defined( 'ABSPATH' ) ) exit;
10
 
11
- class TCM_Logger {
12
  private $name;
13
  private $context=array();
14
 
15
- public function __construct($name='TCM') {
16
- $this->$name=$name;
 
17
  }
18
 
19
  public function pushContext($context) {
@@ -37,15 +33,21 @@ class TCM_Logger {
37
  $this->write('[ERROR]', $message, $v1, $v2, $v3, $v4, $v5, $v6);
38
  }
39
  private function dump($v) {
 
 
 
40
  if($v!=NULL) {
41
  if(is_array($v) || is_object($v)) {
42
  $v=print_r($v, TRUE);
43
  }
44
  }
 
 
 
45
  return $v;
46
  }
47
  private function write($verbosity, $message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL, $v6=NULL) {
48
- global $tcm;
49
 
50
  $text=sprintf($message
51
  , $this->dump($v1)
@@ -59,12 +61,12 @@ class TCM_Logger {
59
  $message.='{'.$this->context[count($this->context)-1].'} ';
60
  }
61
  $message="\n".$message.$text;
62
- if(!$tcm->Options->isLoggerEnable()) {
63
  return $message;
64
  }
65
 
66
  $hasErrors=false;
67
- $filename=TCM_PLUGIN_ROOT."logs/".$this->name."_".date("Ym").".txt";
68
  if (!$handle = fopen($filename, 'a')) {
69
  $hasErrors=true;
70
  }
1
  <?php
2
+
 
 
 
 
 
3
  // Exit if accessed directly
4
  if ( ! defined( 'ABSPATH' ) ) exit;
5
 
6
+ class TCMP_Logger {
7
  private $name;
8
  private $context=array();
9
 
10
+ public function __construct($name='TCMP') {
11
+ if($name=='') $name='TCMP';
12
+ $this->name=$name;
13
  }
14
 
15
  public function pushContext($context) {
33
  $this->write('[ERROR]', $message, $v1, $v2, $v3, $v4, $v5, $v6);
34
  }
35
  private function dump($v) {
36
+ if(is_array($v) && count($v)==0) {
37
+ $v='[]';
38
+ }
39
  if($v!=NULL) {
40
  if(is_array($v) || is_object($v)) {
41
  $v=print_r($v, TRUE);
42
  }
43
  }
44
+ if(is_bool($v)) {
45
+ $v=($v ? 'TRUE' : 'FALSE');
46
+ }
47
  return $v;
48
  }
49
  private function write($verbosity, $message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL, $v6=NULL) {
50
+ global $tcmp;
51
 
52
  $text=sprintf($message
53
  , $this->dump($v1)
61
  $message.='{'.$this->context[count($this->context)-1].'} ';
62
  }
63
  $message="\n".$message.$text;
64
+ if(!$tcmp->Options->isLoggerEnable()) {
65
  return $message;
66
  }
67
 
68
  $hasErrors=false;
69
+ $filename=TCMP_PLUGIN_DIR."logs/".$this->name."_".date("Ym").".txt";
70
  if (!$handle = fopen($filename, 'a')) {
71
  $hasErrors=true;
72
  }
includes/classes/utils/MobileDetect.php ADDED
@@ -0,0 +1,1435 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Mobile Detect Library
4
+ * =====================
5
+ *
6
+ * Motto: "Every business should have a mobile detection script to detect mobile readers"
7
+ *
8
+ * Mobile_Detect is a lightweight PHP class for detecting mobile devices (including tablets).
9
+ * It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.
10
+ *
11
+ * @author Current authors: Serban Ghita <serbanghita@gmail.com>
12
+ * Nick Ilyin <nick.ilyin@gmail.com>
13
+ *
14
+ * Original author: Victor Stanciu <vic.stanciu@gmail.com>
15
+ *
16
+ * @license Code and contributions have 'MIT License'
17
+ * More details: https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE.txt
18
+ *
19
+ * @link Homepage: http://mobiledetect.net
20
+ * GitHub Repo: https://github.com/serbanghita/Mobile-Detect
21
+ * Google Code: http://code.google.com/p/php-mobile-detect/
22
+ * README: https://github.com/serbanghita/Mobile-Detect/blob/master/README.md
23
+ * HOWTO: https://github.com/serbanghita/Mobile-Detect/wiki/Code-examples
24
+ *
25
+ * @version 2.8.19
26
+ */
27
+
28
+ class TCMP_Mobile_Detect {
29
+ /**
30
+ * Mobile detection type.
31
+ *
32
+ * @deprecated since version 2.6.9
33
+ */
34
+ const DETECTION_TYPE_MOBILE = 'mobile';
35
+
36
+ /**
37
+ * Extended detection type.
38
+ *
39
+ * @deprecated since version 2.6.9
40
+ */
41
+ const DETECTION_TYPE_EXTENDED = 'extended';
42
+
43
+ /**
44
+ * A frequently used regular expression to extract version #s.
45
+ *
46
+ * @deprecated since version 2.6.9
47
+ */
48
+ const VER = '([\w._\+]+)';
49
+
50
+ /**
51
+ * Top-level device.
52
+ */
53
+ const MOBILE_GRADE_A = 'A';
54
+
55
+ /**
56
+ * Mid-level device.
57
+ */
58
+ const MOBILE_GRADE_B = 'B';
59
+
60
+ /**
61
+ * Low-level device.
62
+ */
63
+ const MOBILE_GRADE_C = 'C';
64
+
65
+ /**
66
+ * Stores the version number of the current release.
67
+ */
68
+ const VERSION = '2.8.19';
69
+
70
+ /**
71
+ * A type for the version() method indicating a string return value.
72
+ */
73
+ const VERSION_TYPE_STRING = 'text';
74
+
75
+ /**
76
+ * A type for the version() method indicating a float return value.
77
+ */
78
+ const VERSION_TYPE_FLOAT = 'float';
79
+
80
+ /**
81
+ * A cache for resolved matches
82
+ * @var array
83
+ */
84
+ protected $cache = array();
85
+
86
+ /**
87
+ * The User-Agent HTTP header is stored in here.
88
+ * @var string
89
+ */
90
+ protected $userAgent = null;
91
+
92
+ /**
93
+ * HTTP headers in the PHP-flavor. So HTTP_USER_AGENT and SERVER_SOFTWARE.
94
+ * @var array
95
+ */
96
+ protected $httpHeaders = array();
97
+
98
+ /**
99
+ * CloudFront headers. E.g. CloudFront-Is-Desktop-Viewer, CloudFront-Is-Mobile-Viewer & CloudFront-Is-Tablet-Viewer.
100
+ * @var array
101
+ */
102
+ protected $cloudfrontHeaders = array();
103
+
104
+ /**
105
+ * The matching Regex.
106
+ * This is good for debug.
107
+ * @var string
108
+ */
109
+ protected $matchingRegex = null;
110
+
111
+ /**
112
+ * The matches extracted from the regex expression.
113
+ * This is good for debug.
114
+ * @var string
115
+ */
116
+ protected $matchesArray = null;
117
+
118
+ /**
119
+ * The detection type, using self::DETECTION_TYPE_MOBILE or self::DETECTION_TYPE_EXTENDED.
120
+ *
121
+ * @deprecated since version 2.6.9
122
+ *
123
+ * @var string
124
+ */
125
+ protected $detectionType = self::DETECTION_TYPE_MOBILE;
126
+
127
+ /**
128
+ * HTTP headers that trigger the 'isMobile' detection
129
+ * to be true.
130
+ *
131
+ * @var array
132
+ */
133
+ protected static $mobileHeaders = array(
134
+
135
+ 'HTTP_ACCEPT' => array('matches' => array(
136
+ // Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/
137
+ 'application/x-obml2d',
138
+ // BlackBerry devices.
139
+ 'application/vnd.rim.html',
140
+ 'text/vnd.wap.wml',
141
+ 'application/vnd.wap.xhtml+xml'
142
+ )),
143
+ 'HTTP_X_WAP_PROFILE' => null,
144
+ 'HTTP_X_WAP_CLIENTID' => null,
145
+ 'HTTP_WAP_CONNECTION' => null,
146
+ 'HTTP_PROFILE' => null,
147
+ // Reported by Opera on Nokia devices (eg. C3).
148
+ 'HTTP_X_OPERAMINI_PHONE_UA' => null,
149
+ 'HTTP_X_NOKIA_GATEWAY_ID' => null,
150
+ 'HTTP_X_ORANGE_ID' => null,
151
+ 'HTTP_X_VODAFONE_3GPDPCONTEXT' => null,
152
+ 'HTTP_X_HUAWEI_USERID' => null,
153
+ // Reported by Windows Smartphones.
154
+ 'HTTP_UA_OS' => null,
155
+ // Reported by Verizon, Vodafone proxy system.
156
+ 'HTTP_X_MOBILE_GATEWAY' => null,
157
+ // Seen this on HTC Sensation. SensationXE_Beats_Z715e.
158
+ 'HTTP_X_ATT_DEVICEID' => null,
159
+ // Seen this on a HTC.
160
+ 'HTTP_UA_CPU' => array('matches' => array('ARM')),
161
+ );
162
+
163
+ /**
164
+ * List of mobile devices (phones).
165
+ *
166
+ * @var array
167
+ */
168
+ protected static $phoneDevices = array(
169
+ 'iPhone' => '\biPhone\b|\biPod\b', // |\biTunes
170
+ 'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+',
171
+ 'HTC' => 'HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b|T-Mobile G1|Z520m',
172
+ 'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6',
173
+ // @todo: Is 'Dell Streak' a tablet or a phone? ;)
174
+ 'Dell' => 'Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b',
175
+ 'Motorola' => 'Motorola|DROIDX|DROID BIONIC|\bDroid\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\bMoto E\b',
176
+ 'Samsung' => 'Samsung|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205',
177
+ 'LG' => '\bLG\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)',
178
+ 'Sony' => 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533',
179
+ 'Asus' => 'Asus.*Galaxy|PadFone.*Mobile',
180
+ // http://www.micromaxinfo.com/mobiles/smartphones
181
+ // Added because the codes might conflict with Acer Tablets.
182
+ 'Micromax' => 'Micromax.*\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\b',
183
+ // @todo Complete the regex.
184
+ 'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ;
185
+ 'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun ;)
186
+ // http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH)
187
+ // Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android.
188
+ 'Pantech' => 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790',
189
+ // http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones.
190
+ 'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250',
191
+ // http://fr.wikomobile.com
192
+ 'Wiko' => 'KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM',
193
+ 'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)',
194
+ // Added simvalley mobile just for fun. They have some interesting devices.
195
+ // http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html
196
+ 'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b',
197
+ // Wolfgang - a brand that is sold by Aldi supermarkets.
198
+ // http://www.wolfgangmobile.com/
199
+ 'Wolfgang' => 'AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q',
200
+ 'Alcatel' => 'Alcatel',
201
+ 'Nintendo' => 'Nintendo 3DS',
202
+ // http://en.wikipedia.org/wiki/Amoi
203
+ 'Amoi' => 'Amoi',
204
+ // http://en.wikipedia.org/wiki/INQ
205
+ 'INQ' => 'INQ',
206
+ // @Tapatalk is a mobile app; http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039
207
+ 'GenericPhone' => 'Tapatalk|PDA;|SAGEM|\bmmp\b|pocket|\bpsp\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\bwap\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser',
208
+ );
209
+
210
+ /**
211
+ * List of tablet devices.
212
+ *
213
+ * @var array
214
+ */
215
+ protected static $tabletDevices = array(
216
+ // @todo: check for mobile friendly emails topic.
217
+ 'iPad' => 'iPad|iPad.*Mobile',
218
+ // Removed |^.*Android.*Nexus(?!(?:Mobile).)*$
219
+ // @see #442
220
+ 'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)',
221
+ 'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715', // SCH-P709|SCH-P729|SM-T2558|GT-I9205 - Samsung Mega - treat them like a regular phone.
222
+ // http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html
223
+ 'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI)\b',
224
+ // Only the Surface tablets with Windows RT are considered mobile.
225
+ // http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx
226
+ 'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)',
227
+ // http://shopping1.hp.com/is-bin/INTERSHOP.enfinity/WFS/WW-USSMBPublicStore-Site/en_US/-/USD/ViewStandardCatalog-Browse?CatalogCategoryID=JfIQ7EN5lqMAAAEyDcJUDwMT
228
+ 'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10',
229
+ // Watch out for PadFone, see #132.
230
+ // http://www.asus.com/de/Tablets_Mobile/Memo_Pad_Products/
231
+ 'AsusTablet' => '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b|\bK00C\b|\bK00E\b|\bK00L\b|TX201LA|ME176C|ME102A|\bM80TA\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K017 |ME572C|ME103K|ME170C|ME171C|\bME70C\b|ME581C|ME581CL|ME8510C|ME181C',
232
+ 'BlackBerryTablet' => 'PlayBook|RIM Tablet',
233
+ 'HTCtablet' => 'HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410',
234
+ 'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617',
235
+ 'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2',
236
+ // http://www.acer.ro/ac/ro/RO/content/drivers
237
+ // http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer)
238
+ // http://us.acer.com/ac/en/US/content/group/tablets
239
+ // http://www.acer.de/ac/de/DE/content/models/tablets/
240
+ // Can conflict with Micromax and Motorola phones codes.
241
+ 'AcerTablet' => 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\b|W3-810|\bA3-A10\b|\bA3-A11\b',
242
+ // http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/
243
+ // http://us.toshiba.com/tablets/tablet-finder
244
+ // http://www.toshiba.co.jp/regza/tablet/
245
+ 'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO',
246
+ // http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html
247
+ // http://www.lg.com/us/tablets
248
+ 'LGTablet' => '\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\b',
249
+ 'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b',
250
+ // Prestigio Tablets http://www.prestigio.com/support
251
+ 'PrestigioTablet' => 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002',
252
+ // http://support.lenovo.com/en_GB/downloads/default.page?#
253
+ 'LenovoTablet' => 'Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)',
254
+ // http://www.dell.com/support/home/us/en/04/Products/tab_mob/tablets
255
+ 'DellTablet' => 'Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7',
256
+ // http://www.yarvik.com/en/matrix/tablets/
257
+ 'YarvikTablet' => 'Android.*\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\b',
258
+ 'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB',
259
+ 'ArnovaTablet' => 'AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2',
260
+ // http://www.intenso.de/kategorie_en.php?kategorie=33
261
+ // @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate
262
+ 'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004',
263
+ // IRU.ru Tablets http://www.iru.ru/catalog/soho/planetable/
264
+ 'IRUTablet' => 'M702pro',
265
+ 'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b',
266
+ // http://www.e-boda.ro/tablete-pc.html
267
+ 'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)',
268
+ // http://www.allview.ro/produse/droseries/lista-tablete-pc/
269
+ 'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)',
270
+ // http://wiki.archosfans.com/index.php?title=Main_Page
271
+ 'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b',
272
+ // http://www.ainol.com/plugin.php?identifier=ainol&module=product
273
+ 'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark',
274
+ // @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER
275
+ // Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser
276
+ // http://www.sony.jp/support/tablet/
277
+ 'SonyTablet' => 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31',
278
+ // http://www.support.philips.com/support/catalog/worldproducts.jsp?userLanguage=en&userCountry=cn&categoryid=3G_LTE_TABLET_SU_CN_CARE&title=3G%20tablets%20/%20LTE%20range&_dyncharset=UTF-8
279
+ 'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b',
280
+ // db + http://www.cube-tablet.com/buy-products.html
281
+ 'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT',
282
+ // http://www.cobyusa.com/?p=pcat&pcat_id=3001
283
+ 'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010',
284
+ // http://www.match.net.cn/products.asp
285
+ 'MIDTablet' => 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733',
286
+ // http://www.msi.com/support
287
+ // @todo Research the Windows Tablets.
288
+ 'MSITablet' => 'MSI \b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\b',
289
+ // @todo http://www.kyoceramobile.com/support/drivers/
290
+ // 'KyoceraTablet' => null,
291
+ // @todo http://intexuae.com/index.php/category/mobile-devices/tablets-products/
292
+ // 'IntextTablet' => null,
293
+ // http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets)
294
+ // http://www.imp3.net/14/show.php?itemid=20454
295
+ 'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)',
296
+ // http://www.rock-chips.com/index.php?do=prod&pid=2
297
+ 'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A',
298
+ // http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/
299
+ 'FlyTablet' => 'IQ310|Fly Vision',
300
+ // http://www.bqreaders.com/gb/tablets-prices-sale.html
301
+ 'bqTablet' => 'Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus',
302
+ // http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290
303
+ // http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets)
304
+ 'HuaweiTablet' => 'MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim',
305
+ // Nec or Medias Tab
306
+ 'NecTablet' => '\bN-06D|\bN-08D',
307
+ // Pantech Tablets: http://www.pantechusa.com/phones/
308
+ 'PantechTablet' => 'Pantech.*P4100',
309
+ // Broncho Tablets: http://www.broncho.cn/ (hard to find)
310
+ 'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)',
311
+ // http://versusuk.com/support.html
312
+ 'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b',
313
+ // http://www.zync.in/index.php/our-products/tablet-phablets
314
+ 'ZyncTablet' => 'z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900',
315
+ // http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/
316
+ 'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA',
317
+ // https://www.nabitablet.com/
318
+ 'NabiTablet' => 'Android.*\bNabi',
319
+ 'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build',
320
+ // French Danew Tablets http://www.danew.com/produits-tablette.php
321
+ 'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b',
322
+ // Texet Tablets and Readers http://www.texet.ru/tablet/
323
+ 'TexetTablet' => 'NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE',
324
+ // Avoid detecting 'PLAYSTATION 3' as mobile.
325
+ 'PlaystationTablet' => 'Playstation.*(Portable|Vita)',
326
+ // http://www.trekstor.de/surftabs.html
327
+ 'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab',
328
+ // http://www.pyleaudio.com/Products.aspx?%2fproducts%2fPersonal-Electronics%2fTablets
329
+ 'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b',
330
+ // http://www.advandigital.com/index.php?link=content-product&jns=JP001
331
+ // because of the short codenames we have to include whitespaces to reduce the possible conflicts.
332
+ 'AdvanTablet' => 'Android.* \b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\b ',
333
+ // http://www.danytech.com/category/tablet-pc
334
+ 'DanyTechTablet' => 'Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1',
335
+ // http://www.galapad.net/product.html
336
+ 'GalapadTablet' => 'Android.*\bG1\b',
337
+ // http://www.micromaxinfo.com/tablet/funbook
338
+ 'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b',
339
+ // http://www.karbonnmobiles.com/products_tablet.php
340
+ 'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b',
341
+ // http://www.myallfine.com/Products.asp
342
+ 'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide',
343
+ // http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr=
344
+ 'PROSCANTablet' => '\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\b',
345
+ // http://www.yonesnav.com/products/products.php
346
+ 'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026',
347
+ // http://www.cjshowroom.com/eproducts.aspx?classcode=004001001
348
+ // China manufacturer makes tablets for different small brands (eg. http://www.zeepad.net/index.html)
349
+ 'ChangJiaTablet' => 'TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503',
350
+ // http://www.gloryunion.cn/products.asp
351
+ // http://www.allwinnertech.com/en/apply/mobile.html
352
+ // http://www.ptcl.com.pk/pd_content.php?pd_id=284 (EVOTAB)
353
+ // @todo: Softwiner tablets?
354
+ // aka. Cute or Cool tablets. Not sure yet, must research to avoid collisions.
355
+ 'GUTablet' => 'TX-A1301|TX-M9002|Q702|kf026', // A12R|D75A|D77|D79|R83|A95|A106C|R15|A75|A76|D71|D72|R71|R73|R77|D82|R85|D92|A97|D92|R91|A10F|A77F|W71F|A78F|W78F|W81F|A97F|W91F|W97F|R16G|C72|C73E|K72|K73|R96G
356
+ // http://www.pointofview-online.com/showroom.php?shop_mode=product_listing&category_id=118
357
+ 'PointOfViewTablet' => 'TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10',
358
+ // http://www.overmax.pl/pl/katalog-produktow,p8/tablety,c14/
359
+ // @todo: add more tests.
360
+ 'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)',
361
+ // http://hclmetablet.com/India/index.php
362
+ 'HCLTablet' => 'HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync',
363
+ // http://www.edigital.hu/Tablet_es_e-book_olvaso/Tablet-c18385.html
364
+ 'DPSTablet' => 'DPS Dream 9|DPS Dual 7',
365
+ // http://www.visture.com/index.asp
366
+ 'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10',
367
+ // http://www.mijncresta.nl/tablet
368
+ 'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989',
369
+ // MediaTek - http://www.mediatek.com/_en/01_products/02_proSys.php?cata_sn=1&cata1_sn=1&cata2_sn=309
370
+ 'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b',
371
+ // Concorde tab
372
+ 'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan',
373
+ // GoClever Tablets - http://www.goclever.com/uk/products,c1/tablet,c5/
374
+ 'GoCleverTablet' => 'GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042',
375
+ // Modecom Tablets - http://www.modecom.eu/tablets/portal/
376
+ 'ModecomTablet' => 'FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003',
377
+ // Vonino Tablets - http://www.vonino.eu/tablets
378
+ 'VoninoTablet' => '\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\bQ8\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\b',
379
+ // ECS Tablets - http://www.ecs.com.tw/ECSWebSite/Product/Product_Tablet_List.aspx?CategoryID=14&MenuID=107&childid=M_107&LanID=0
380
+ 'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1',
381
+ // Storex Tablets - http://storex.fr/espace_client/support.html
382
+ // @note: no need to add all the tablet codes since they are guided by the first regex.
383
+ 'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab',
384
+ // Generic Vodafone tablets.
385
+ 'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7',
386
+ // French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb
387
+ // Aka: http://www.essentielb.fr/
388
+ 'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2',
389
+ // Ross & Moor - http://ross-moor.ru/
390
+ 'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711',
391
+ // i-mobile http://product.i-mobilephone.com/Mobile_Device
392
+ 'iMobileTablet' => 'i-mobile i-note',
393
+ // http://www.tolino.de/de/vergleichen/
394
+ 'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine',
395
+ // AudioSonic - a Kmart brand
396
+ // http://www.kmart.com.au/webapp/wcs/stores/servlet/Search?langId=-1&storeId=10701&catalogId=10001&categoryId=193001&pageSize=72&currentPage=1&searchCategory=193001%2b4294965664&sortBy=p_MaxPrice%7c1
397
+ 'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b',
398
+ // AMPE Tablets - http://www.ampe.com.my/product-category/tablets/
399
+ // @todo: add them gradually to avoid conflicts.
400
+ 'AMPETablet' => 'Android.* A78 ',
401
+ // Skk Mobile - http://skkmobile.com.ph/product_tablets.php
402
+ 'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)',
403
+ // Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1
404
+ 'TecnoTablet' => 'TECNO P9',
405
+ // JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3
406
+ 'JXDTablet' => 'Android.*\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b',
407
+ // i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/
408
+ 'iJoyTablet' => 'Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)',
409
+ // http://www.intracon.eu/tablet
410
+ 'FX2Tablet' => 'FX2 PAD7|FX2 PAD10',
411
+ // http://www.xoro.de/produkte/
412
+ // @note: Might be the same brand with 'Simply tablets'
413
+ 'XoroTablet' => 'KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151',
414
+ // http://www1.viewsonic.com/products/computing/tablets/
415
+ 'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a',
416
+ // http://www.odys.de/web/internet-tablet_en.html
417
+ 'OdysTablet' => 'LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\bXELIO\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10',
418
+ // http://www.captiva-power.de/products.html#tablets-en
419
+ 'CaptivaTablet' => 'CAPTIVA PAD',
420
+ // IconBIT - http://www.iconbit.com/products/tablets/
421
+ 'IconbitTablet' => 'NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S',
422
+ // http://www.teclast.com/topic.php?channelID=70&topicID=140&pid=63
423
+ 'TeclastTablet' => 'T98 4G|\bP80\b|\bX90HD\b|X98 Air|X98 Air 3G|\bX89\b|P80 3G|\bX80h\b|P98 Air|\bX89HD\b|P98 3G|\bP90HD\b|P89 3G|X98 3G|\bP70h\b|P79HD 3G|G18d 3G|\bP79HD\b|\bP89s\b|\bA88\b|\bP10HD\b|\bP19HD\b|G18 3G|\bP78HD\b|\bA78\b|\bP75\b|G17s 3G|G17h 3G|\bP85t\b|\bP90\b|\bP11\b|\bP98t\b|\bP98HD\b|\bG18d\b|\bP85s\b|\bP11HD\b|\bP88s\b|\bA80HD\b|\bA80se\b|\bA10h\b|\bP89\b|\bP78s\b|\bG18\b|\bP85\b|\bA70h\b|\bA70\b|\bG17\b|\bP18\b|\bA80s\b|\bA11s\b|\bP88HD\b|\bA80h\b|\bP76s\b|\bP76h\b|\bP98\b|\bA10HD\b|\bP78\b|\bP88\b|\bA11\b|\bA10t\b|\bP76a\b|\bP76t\b|\bP76e\b|\bP85HD\b|\bP85a\b|\bP86\b|\bP75HD\b|\bP76v\b|\bA12\b|\bP75a\b|\bA15\b|\bP76Ti\b|\bP81HD\b|\bA10\b|\bT760VE\b|\bT720HD\b|\bP76\b|\bP73\b|\bP71\b|\bP72\b|\bT720SE\b|\bC520Ti\b|\bT760\b|\bT720VE\b|T720-3GE|T720-WiFi',
424
+ // Onda - http://www.onda-tablet.com/buy-android-onda.html?dir=desc&limit=all&order=price
425
+ 'OndaTablet' => '\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\b[\s]+',
426
+ 'JaytechTablet' => 'TPC-PA762',
427
+ 'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010',
428
+ // http://www.digma.ru/support/download/
429
+ // @todo: Ebooks also (if requested)
430
+ 'DigmaTablet' => '\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\b',
431
+ // http://www.evolioshop.com/ro/tablete-pc.html
432
+ // http://www.evolio.ro/support/downloads_static.html?cat=2
433
+ // @todo: Research some more
434
+ 'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b',
435
+ // @todo http://www.lavamobiles.com/tablets-data-cards
436
+ 'LavaTablet' => 'QPAD E704|\bIvoryS\b|E-TAB IVORY|\bE-TAB\b',
437
+ 'AocTablet' => 'MW0811|MW0812|MW0922|MTK8382',
438
+ // https://www.celkonmobiles.com/?_a=categoryphones&sid=2
439
+ 'CelkonTablet' => 'CT695|CT888|CT[\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\bCT-1\b',
440
+ // http://www.wolderelectronics.com/productos/manuales-y-guias-rapidas/categoria-2-miTab
441
+ 'WolderTablet' => 'miTab \b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\b',
442
+ // http://www.mi.com/en
443
+ 'MiTablet' => '\bMI PAD\b|\bHM NOTE 1W\b',
444
+ // http://www.nbru.cn/index.html
445
+ 'NibiruTablet' => 'Nibiru M1|Nibiru Jupiter One',
446
+ // http://navroad.com/products/produkty/tablety/
447
+ 'NexoTablet' => 'NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI',
448
+ // http://leader-online.com/new_site/product-category/tablets/
449
+ // http://www.leader-online.net.au/List/Tablet
450
+ 'LeaderTablet' => 'TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100',
451
+ // http://www.datawind.com/ubislate/
452
+ 'UbislateTablet' => 'UbiSlate[\s]?7C',
453
+ // http://www.pocketbook-int.com/ru/support
454
+ 'PocketBookTablet' => 'Pocketbook',
455
+ // http://www.tesco.com/direct/hudl/
456
+ 'Hudl' => 'Hudl HT7S3|Hudl 2',
457
+ // http://www.telstra.com.au/home-phone/thub-2/
458
+ 'TelstraTablet' => 'T-Hub2',
459
+ 'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\bM6pro\b|CT1020W|arc 10HD|\bJolla\b|\bTP750\b'
460
+ );
461
+
462
+ /**
463
+ * List of mobile Operating Systems.
464
+ *
465
+ * @var array
466
+ */
467
+ protected static $operatingSystems = array(
468
+ 'AndroidOS' => 'Android',
469
+ 'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os',
470
+ 'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino',
471
+ 'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b',
472
+ // @reference: http://en.wikipedia.org/wiki/Windows_Mobile
473
+ 'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;',
474
+ // @reference: http://en.wikipedia.org/wiki/Windows_Phone
475
+ // http://wifeng.cn/?r=blog&a=view&id=106
476
+ // http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx
477
+ // http://msdn.microsoft.com/library/ms537503.aspx
478
+ // https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
479
+ 'WindowsPhoneOS' => 'Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;',
480
+ 'iOS' => '\biPhone.*Mobile|\biPod|\biPad',
481
+ // http://en.wikipedia.org/wiki/MeeGo
482
+ // @todo: research MeeGo in UAs
483
+ 'MeeGoOS' => 'MeeGo',
484
+ // http://en.wikipedia.org/wiki/Maemo
485
+ // @todo: research Maemo in UAs
486
+ 'MaemoOS' => 'Maemo',
487
+ 'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135
488
+ 'webOS' => 'webOS|hpwOS',
489
+ 'badaOS' => '\bBada\b',
490
+ 'BREWOS' => 'BREW',
491
+ );
492
+
493
+ /**
494
+ * List of mobile User Agents.
495
+ *
496
+ * @var array
497
+ */
498
+ protected static $browsers = array(
499
+ // @reference: https://developers.google.com/chrome/mobile/docs/user-agent
500
+ 'Chrome' => '\bCrMo\b|CriOS|Android.*Chrome/[.0-9]* (Mobile)?',
501
+ 'Dolfin' => '\bDolfin\b',
502
+ 'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+|Coast/[0-9.]+',
503
+ 'Skyfire' => 'Skyfire',
504
+ 'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+
505
+ 'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile',
506
+ 'Bolt' => 'bolt',
507
+ 'TeaShark' => 'teashark',
508
+ 'Blazer' => 'Blazer',
509
+ // @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3
510
+ 'Safari' => 'Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari',
511
+ // http://en.wikipedia.org/wiki/Midori_(web_browser)
512
+ //'Midori' => 'midori',
513
+ 'Tizen' => 'Tizen',
514
+ 'UCBrowser' => 'UC.*Browser|UCWEB',
515
+ 'baiduboxapp' => 'baiduboxapp',
516
+ 'baidubrowser' => 'baidubrowser',
517
+ // https://github.com/serbanghita/Mobile-Detect/issues/7
518
+ 'DiigoBrowser' => 'DiigoBrowser',
519
+ // http://www.puffinbrowser.com/index.php
520
+ 'Puffin' => 'Puffin',
521
+ // http://mercury-browser.com/index.html
522
+ 'Mercury' => '\bMercury\b',
523
+ // http://en.wikipedia.org/wiki/Obigo_Browser
524
+ 'ObigoBrowser' => 'Obigo',
525
+ // http://en.wikipedia.org/wiki/NetFront
526
+ 'NetFront' => 'NF-Browser',
527
+ // @reference: http://en.wikipedia.org/wiki/Minimo
528
+ // http://en.wikipedia.org/wiki/Vision_Mobile_Browser
529
+ 'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger',
530
+ );
531
+
532
+ /**
533
+ * Utilities.
534
+ *
535
+ * @var array
536
+ */
537
+ protected static $utilities = array(
538
+ // Experimental. When a mobile device wants to switch to 'Desktop Mode'.
539
+ // http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/
540
+ // https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011
541
+ // https://developers.facebook.com/docs/sharing/best-practices
542
+ 'Bot' => 'Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom',
543
+ 'MobileBot' => 'Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker/M1A1-R2D2',
544
+ 'DesktopMode' => 'WPDesktop',
545
+ 'TV' => 'SonyDTV|HbbTV', // experimental
546
+ 'WebKit' => '(webkit)[ /]([\w.]+)',
547
+ // @todo: Include JXD consoles.
548
+ 'Console' => '\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\b',
549
+ 'Watch' => 'SM-V700',
550
+ );
551
+
552
+ /**
553
+ * All possible HTTP headers that represent the
554
+ * User-Agent string.
555
+ *
556
+ * @var array
557
+ */
558
+ protected static $uaHttpHeaders = array(
559
+ // The default User-Agent string.
560
+ 'HTTP_USER_AGENT',
561
+ // Header can occur on devices using Opera Mini.
562
+ 'HTTP_X_OPERAMINI_PHONE_UA',
563
+ // Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/
564
+ 'HTTP_X_DEVICE_USER_AGENT',
565
+ 'HTTP_X_ORIGINAL_USER_AGENT',
566
+ 'HTTP_X_SKYFIRE_PHONE',
567
+ 'HTTP_X_BOLT_PHONE_UA',
568
+ 'HTTP_DEVICE_STOCK_UA',
569
+ 'HTTP_X_UCBROWSER_DEVICE_UA'
570
+ );
571
+
572
+ /**
573
+ * The individual segments that could exist in a User-Agent string. VER refers to the regular
574
+ * expression defined in the constant self::VER.
575
+ *
576
+ * @var array
577
+ */
578
+ protected static $properties = array(
579
+
580
+ // Build
581
+ 'Mobile' => 'Mobile/[VER]',
582
+ 'Build' => 'Build/[VER]',
583
+ 'Version' => 'Version/[VER]',
584
+ 'VendorID' => 'VendorID/[VER]',
585
+
586
+ // Devices
587
+ 'iPad' => 'iPad.*CPU[a-z ]+[VER]',
588
+ 'iPhone' => 'iPhone.*CPU[a-z ]+[VER]',
589
+ 'iPod' => 'iPod.*CPU[a-z ]+[VER]',
590
+ //'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'),
591
+ 'Kindle' => 'Kindle/[VER]',
592
+
593
+ // Browser
594
+ 'Chrome' => array('Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]'),
595
+ 'Coast' => array('Coast/[VER]'),
596
+ 'Dolfin' => 'Dolfin/[VER]',
597
+ // @reference: https://developer.mozilla.org/en-US/docs/User_Agent_Strings_Reference
598
+ 'Firefox' => 'Firefox/[VER]',
599
+ 'Fennec' => 'Fennec/[VER]',
600
+ // http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx
601
+ // https://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx
602
+ 'IE' => array('IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];', 'Trident/[0-9.]+;.*rv:[VER]'),
603
+ // http://en.wikipedia.org/wiki/NetFront
604
+ 'NetFront' => 'NetFront/[VER]',
605
+ 'NokiaBrowser' => 'NokiaBrowser/[VER]',
606
+ 'Opera' => array( ' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]' ),
607
+ 'Opera Mini' => 'Opera Mini/[VER]',
608
+ 'Opera Mobi' => 'Version/[VER]',
609
+ 'UC Browser' => 'UC Browser[VER]',
610
+ 'MQQBrowser' => 'MQQBrowser/[VER]',
611
+ 'MicroMessenger' => 'MicroMessenger/[VER]',
612
+ 'baiduboxapp' => 'baiduboxapp/[VER]',
613
+ 'baidubrowser' => 'baidubrowser/[VER]',
614
+ 'Iron' => 'Iron/[VER]',
615
+ // @note: Safari 7534.48.3 is actually Version 5.1.
616
+ // @note: On BlackBerry the Version is overwriten by the OS.
617
+ 'Safari' => array( 'Version/[VER]', 'Safari/[VER]' ),
618
+ 'Skyfire' => 'Skyfire/[VER]',
619
+ 'Tizen' => 'Tizen/[VER]',
620
+ 'Webkit' => 'webkit[ /][VER]',
621
+
622
+ // Engine
623
+ 'Gecko' => 'Gecko/[VER]',
624
+ 'Trident' => 'Trident/[VER]',
625
+ 'Presto' => 'Presto/[VER]',
626
+
627
+ // OS
628
+ 'iOS' => ' \bi?OS\b [VER][ ;]{1}',
629
+ 'Android' => 'Android [VER]',
630
+ 'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'),
631
+ 'BREW' => 'BREW [VER]',
632
+ 'Java' => 'Java/[VER]',
633
+ // @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx
634
+ // @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases
635
+ 'Windows Phone OS' => array( 'Windows Phone OS [VER]', 'Windows Phone [VER]'),
636
+ 'Windows Phone' => 'Windows Phone [VER]',
637
+ 'Windows CE' => 'Windows CE/[VER]',
638
+ // http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd
639
+ 'Windows NT' => 'Windows NT [VER]',
640
+ 'Symbian' => array('SymbianOS/[VER]', 'Symbian/[VER]'),
641
+ 'webOS' => array('webOS/[VER]', 'hpwOS/[VER];'),
642
+ );
643
+
644
+ /**
645
+ * Construct an instance of this class.
646
+ *
647
+ * @param array $headers Specify the headers as injection. Should be PHP _SERVER flavored.
648
+ * If left empty, will use the global _SERVER['HTTP_*'] vars instead.
649
+ * @param string $userAgent Inject the User-Agent header. If null, will use HTTP_USER_AGENT
650
+ * from the $headers array instead.
651
+ */
652
+ public function __construct(
653
+ array $headers = null,
654
+ $userAgent = null
655
+ ) {
656
+ $this->setHttpHeaders($headers);
657
+ $this->setUserAgent($userAgent);
658
+ }
659
+
660
+ /**
661
+ * Get the current script version.
662
+ * This is useful for the demo.php file,
663
+ * so people can check on what version they are testing
664
+ * for mobile devices.
665
+ *
666
+ * @return string The version number in semantic version format.
667
+ */
668
+ public static function getScriptVersion()
669
+ {
670
+ return self::VERSION;
671
+ }
672
+
673
+ /**
674
+ * Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers.
675
+ *
676
+ * @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract
677
+ * the headers. The default null is left for backwards compatibilty.
678
+ */
679
+ public function setHttpHeaders($httpHeaders = null)
680
+ {
681
+ // use global _SERVER if $httpHeaders aren't defined
682
+ if (!is_array($httpHeaders) || !count($httpHeaders)) {
683
+ $httpHeaders = $_SERVER;
684
+ }
685
+
686
+ // clear existing headers
687
+ $this->httpHeaders = array();
688
+
689
+ // Only save HTTP headers. In PHP land, that means only _SERVER vars that
690
+ // start with HTTP_.
691
+ foreach ($httpHeaders as $key => $value) {
692
+ if (substr($key, 0, 5) === 'HTTP_') {
693
+ $this->httpHeaders[$key] = $value;
694
+ }
695
+ }
696
+
697
+ // In case we're dealing with CloudFront, we need to know.
698
+ $this->setCfHeaders($httpHeaders);
699
+ }
700
+
701
+ /**
702
+ * Retrieves the HTTP headers.
703
+ *
704
+ * @return array
705
+ */
706
+ public function getHttpHeaders()
707
+ {
708
+ return $this->httpHeaders;
709
+ }
710
+
711
+ /**
712
+ * Retrieves a particular header. If it doesn't exist, no exception/error is caused.
713
+ * Simply null is returned.
714
+ *
715
+ * @param string $header The name of the header to retrieve. Can be HTTP compliant such as
716
+ * "User-Agent" or "X-Device-User-Agent" or can be php-esque with the
717
+ * all-caps, HTTP_ prefixed, underscore seperated awesomeness.
718
+ *
719
+ * @return string|null The value of the header.
720
+ */
721
+ public function getHttpHeader($header)
722
+ {
723
+ // are we using PHP-flavored headers?
724
+ if (strpos($header, '_') === false) {
725
+ $header = str_replace('-', '_', $header);
726
+ $header = strtoupper($header);
727
+ }
728
+
729
+ // test the alternate, too
730
+ $altHeader = 'HTTP_' . $header;
731
+
732
+ //Test both the regular and the HTTP_ prefix
733
+ if (isset($this->httpHeaders[$header])) {
734
+ return $this->httpHeaders[$header];
735
+ } elseif (isset($this->httpHeaders[$altHeader])) {
736
+ return $this->httpHeaders[$altHeader];
737
+ }
738
+
739
+ return null;
740
+ }
741
+
742
+ public function getMobileHeaders()
743
+ {
744
+ return self::$mobileHeaders;
745
+ }
746
+
747
+ /**
748
+ * Get all possible HTTP headers that
749
+ * can contain the User-Agent string.
750
+ *
751
+ * @return array List of HTTP headers.
752
+ */
753
+ public function getUaHttpHeaders()
754
+ {
755
+ return self::$uaHttpHeaders;
756
+ }
757
+
758
+
759
+ /**
760
+ * Set CloudFront headers
761
+ * http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-device
762
+ *
763
+ * @param array $cfHeaders List of HTTP headers
764
+ *
765
+ * @return boolean If there were CloudFront headers to be set
766
+ */
767
+ public function setCfHeaders($cfHeaders = null) {
768
+ // use global _SERVER if $cfHeaders aren't defined
769
+ if (!is_array($cfHeaders) || !count($cfHeaders)) {
770
+ $cfHeaders = $_SERVER;
771
+ }
772
+
773
+ // clear existing headers
774
+ $this->cloudfrontHeaders = array();
775
+
776
+ // Only save CLOUDFRONT headers. In PHP land, that means only _SERVER vars that
777
+ // start with cloudfront-.
778
+ $response = false;
779
+ foreach ($cfHeaders as $key => $value) {
780
+ if (substr(strtolower($key), 0, 16) === 'http_cloudfront_') {
781
+ $this->cloudfrontHeaders[strtoupper($key)] = $value;
782
+ $response = true;
783
+ }
784
+ }
785
+
786
+ return $response;
787
+ }
788
+
789
+ /**
790
+ * Retrieves the cloudfront headers.
791
+ *
792
+ * @return array
793
+ */
794
+ public function getCfHeaders()
795
+ {
796
+ return $this->cloudfrontHeaders;
797
+ }
798
+
799
+ /**
800
+ * Set the User-Agent to be used.
801
+ *
802
+ * @param string $userAgent The user agent string to set.
803
+ *
804
+ * @return string|null
805
+ */
806
+ public function setUserAgent($userAgent = null)
807
+ {
808
+ // Invalidate cache due to #375
809
+ $this->cache = array();
810
+
811
+ if (false === empty($userAgent)) {
812
+ return $this->userAgent = $userAgent;
813
+ } else {
814
+ $this->userAgent = null;
815
+ foreach ($this->getUaHttpHeaders() as $altHeader) {
816
+ if (false === empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow. (Serban)
817
+ $this->userAgent .= $this->httpHeaders[$altHeader] . " ";
818
+ }
819
+ }
820
+
821
+ if (!empty($this->userAgent)) {
822
+ return $this->userAgent = trim($this->userAgent);
823
+ }
824
+ }
825
+
826
+ if (count($this->getCfHeaders()) > 0) {
827
+ return $this->userAgent = 'Amazon CloudFront';
828
+ }
829
+ return $this->userAgent = null;
830
+ }
831
+
832
+ /**
833
+ * Retrieve the User-Agent.
834
+ *
835
+ * @return string|null The user agent if it's set.
836
+ */
837
+ public function getUserAgent()
838
+ {
839
+ return $this->userAgent;
840
+ }
841
+
842
+ /**
843
+ * Set the detection type. Must be one of self::DETECTION_TYPE_MOBILE or
844
+ * self::DETECTION_TYPE_EXTENDED. Otherwise, nothing is set.
845
+ *
846
+ * @deprecated since version 2.6.9
847
+ *
848
+ * @param string $type The type. Must be a self::DETECTION_TYPE_* constant. The default
849
+ * parameter is null which will default to self::DETECTION_TYPE_MOBILE.
850
+ */
851
+ public function setDetectionType($type = null)
852
+ {
853
+ if ($type === null) {
854
+ $type = self::DETECTION_TYPE_MOBILE;
855
+ }
856
+
857
+ if ($type !== self::DETECTION_TYPE_MOBILE && $type !== self::DETECTION_TYPE_EXTENDED) {
858
+ return;
859
+ }
860
+
861
+ $this->detectionType = $type;
862
+ }
863
+
864
+ public function getMatchingRegex()
865
+ {
866
+ return $this->matchingRegex;
867
+ }
868
+
869
+ public function getMatchesArray()
870
+ {
871
+ return $this->matchesArray;
872
+ }
873
+
874
+ /**
875
+ * Retrieve the list of known phone devices.
876
+ *
877
+ * @return array List of phone devices.
878
+ */
879
+ public static function getPhoneDevices()
880
+ {
881
+ return self::$phoneDevices;
882
+ }
883
+
884
+ /**
885
+ * Retrieve the list of known tablet devices.
886
+ *
887
+ * @return array List of tablet devices.
888
+ */
889
+ public static function getTabletDevices()
890
+ {
891
+ return self::$tabletDevices;
892
+ }
893
+
894
+ /**
895
+ * Alias for getBrowsers() method.
896
+ *
897
+ * @return array List of user agents.
898
+ */
899
+ public static function getUserAgents()
900
+ {
901
+ return self::getBrowsers();
902
+ }
903
+
904
+ /**
905
+ * Retrieve the list of known browsers. Specifically, the user agents.
906
+ *
907
+ * @return array List of browsers / user agents.
908
+ */
909
+ public static function getBrowsers()
910
+ {
911
+ return self::$browsers;
912
+ }
913
+
914
+ /**
915
+ * Retrieve the list of known utilities.
916
+ *
917
+ * @return array List of utilities.
918
+ */
919
+ public static function getUtilities()
920
+ {
921
+ return self::$utilities;
922
+ }
923
+
924
+ /**
925
+ * Method gets the mobile detection rules. This method is used for the magic methods $detect->is*().
926
+ *
927
+ * @deprecated since version 2.6.9
928
+ *
929
+ * @return array All the rules (but not extended).
930
+ */
931
+ public static function getMobileDetectionRules()
932
+ {
933
+ static $rules;
934
+
935
+ if (!$rules) {
936
+ $rules = array_merge(
937
+ self::$phoneDevices,
938
+ self::$tabletDevices,
939
+ self::$operatingSystems,
940
+ self::$browsers
941
+ );
942
+ }
943
+
944
+ return $rules;
945
+
946
+ }
947
+
948
+ /**
949
+ * Method gets the mobile detection rules + utilities.
950
+ * The reason this is separate is because utilities rules
951
+ * don't necessary imply mobile. This method is used inside
952
+ * the new $detect->is('stuff') method.
953
+ *
954
+ * @deprecated since version 2.6.9
955
+ *
956
+ * @return array All the rules + extended.
957
+ */
958
+ public function getMobileDetectionRulesExtended()
959
+ {
960
+ static $rules;
961
+
962
+ if (!$rules) {
963
+ // Merge all rules together.
964
+ $rules = array_merge(
965
+ self::$phoneDevices,
966
+ self::$tabletDevices,
967
+ self::$operatingSystems,
968
+ self::$browsers,
969
+ self::$utilities
970
+ );
971
+ }
972
+
973
+ return $rules;
974
+ }
975
+
976
+ /**
977
+ * Retrieve the current set of rules.
978
+ *
979
+ * @deprecated since version 2.6.9
980
+ *
981
+ * @return array
982
+ */
983
+ public function getRules()
984
+ {
985
+ if ($this->detectionType == self::DETECTION_TYPE_EXTENDED) {
986
+ return self::getMobileDetectionRulesExtended();
987
+ } else {
988
+ return self::getMobileDetectionRules();
989
+ }
990
+ }
991
+
992
+ /**
993
+ * Retrieve the list of mobile operating systems.
994
+ *
995
+ * @return array The list of mobile operating systems.
996
+ */
997
+ public static function getOperatingSystems()
998
+ {
999
+ return self::$operatingSystems;
1000
+ }
1001
+
1002
+ /**
1003
+ * Check the HTTP headers for signs of mobile.
1004
+ * This is the fastest mobile check possible; it's used
1005
+ * inside isMobile() method.
1006
+ *
1007
+ * @return bool
1008
+ */
1009
+ public function checkHttpHeadersForMobile()
1010
+ {
1011
+
1012
+ foreach ($this->getMobileHeaders() as $mobileHeader => $matchType) {
1013
+ if (isset($this->httpHeaders[$mobileHeader])) {
1014
+ if (is_array($matchType['matches'])) {
1015
+ foreach ($matchType['matches'] as $_match) {
1016
+ if (strpos($this->httpHeaders[$mobileHeader], $_match) !== false) {
1017
+ return true;
1018
+ }
1019
+ }
1020
+
1021
+ return false;
1022
+ } else {
1023
+ return true;
1024
+ }
1025
+ }
1026
+ }
1027
+
1028
+ return false;
1029
+
1030
+ }
1031
+
1032
+ /**
1033
+ * Magic overloading method.
1034
+ *
1035
+ * @method boolean is[...]()
1036
+ * @param string $name
1037
+ * @param array $arguments
1038
+ * @return mixed
1039
+ * @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is'
1040
+ */
1041
+ public function __call($name, $arguments)
1042
+ {
1043
+ // make sure the name starts with 'is', otherwise
1044
+ if (substr($name, 0, 2) !== 'is') {
1045
+ throw new BadMethodCallException("No such method exists: $name");
1046
+ }
1047
+
1048
+ $this->setDetectionType(self::DETECTION_TYPE_MOBILE);
1049
+
1050
+ $key = substr($name, 2);
1051
+
1052
+ return $this->matchUAAgainstKey($key);
1053
+ }
1054
+
1055
+ /**
1056
+ * Find a detection rule that matches the current User-agent.
1057
+ *
1058
+ * @param null $userAgent deprecated
1059
+ * @return boolean
1060
+ */
1061
+ protected function matchDetectionRulesAgainstUA($userAgent = null)
1062
+ {
1063
+ // Begin general search.
1064
+ foreach ($this->getRules() as $_regex) {
1065
+ if (empty($_regex)) {
1066
+ continue;
1067
+ }
1068
+
1069
+ if ($this->match($_regex, $userAgent)) {
1070
+ return true;
1071
+ }
1072
+ }
1073
+
1074
+ return false;
1075
+ }
1076
+
1077
+ /**
1078
+ * Search for a certain key in the rules array.
1079
+ * If the key is found then try to match the corresponding
1080
+ * regex against the User-Agent.
1081
+ *
1082
+ * @param string $key
1083
+ *
1084
+ * @return boolean
1085
+ */
1086
+ protected function matchUAAgainstKey($key)
1087
+ {
1088
+ // Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc.
1089
+ $key = strtolower($key);
1090
+ if (false === isset($this->cache[$key])) {
1091
+
1092
+ // change the keys to lower case
1093
+ $_rules = array_change_key_case($this->getRules());
1094
+
1095
+ if (false === empty($_rules[$key])) {
1096
+ $this->cache[$key] = $this->match($_rules[$key]);
1097
+ }
1098
+
1099
+ if (false === isset($this->cache[$key])) {
1100
+ $this->cache[$key] = false;
1101
+ }
1102
+ }
1103
+
1104
+ return $this->cache[$key];
1105
+ }
1106
+
1107
+ /**
1108
+ * Check if the device is mobile.
1109
+ * Returns true if any type of mobile device detected, including special ones
1110
+ * @param null $userAgent deprecated
1111
+ * @param null $httpHeaders deprecated
1112
+ * @return bool
1113
+ */
1114
+ public function isMobile($userAgent = null, $httpHeaders = null)
1115
+ {
1116
+
1117
+ if ($httpHeaders) {
1118
+ $this->setHttpHeaders($httpHeaders);
1119
+ }
1120
+
1121
+ if ($userAgent) {
1122
+ $this->setUserAgent($userAgent);
1123
+ }
1124
+
1125
+ // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
1126
+ if ($this->getUserAgent() === 'Amazon CloudFront') {
1127
+ $cfHeaders = $this->getCfHeaders();
1128
+ if(array_key_exists('HTTP_CLOUDFRONT_IS_MOBILE_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_MOBILE_VIEWER'] === 'true') {
1129
+ return true;
1130
+ }
1131
+ }
1132
+
1133
+ $this->setDetectionType(self::DETECTION_TYPE_MOBILE);
1134
+
1135
+ if ($this->checkHttpHeadersForMobile()) {
1136
+ return true;
1137
+ } else {
1138
+ return $this->matchDetectionRulesAgainstUA();
1139
+ }
1140
+
1141
+ }
1142
+
1143
+ /**
1144
+ * Check if the device is a tablet.
1145
+ * Return true if any type of tablet device is detected.
1146
+ *
1147
+ * @param string $userAgent deprecated
1148
+ * @param array $httpHeaders deprecated
1149
+ * @return bool
1150
+ */
1151
+ public function isTablet($userAgent = null, $httpHeaders = null)
1152
+ {
1153
+ // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
1154
+ if ($this->getUserAgent() === 'Amazon CloudFront') {
1155
+ $cfHeaders = $this->getCfHeaders();
1156
+ if(array_key_exists('HTTP_CLOUDFRONT_IS_TABLET_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_TABLET_VIEWER'] === 'true') {
1157
+ return true;
1158
+ }
1159
+ }
1160
+
1161
+ $this->setDetectionType(self::DETECTION_TYPE_MOBILE);
1162
+
1163
+ foreach (self::$tabletDevices as $_regex) {
1164
+ if ($this->match($_regex, $userAgent)) {
1165
+ return true;
1166
+ }
1167
+ }
1168
+
1169
+ return false;
1170
+ }
1171
+
1172
+ /**
1173
+ * This method checks for a certain property in the
1174
+ * userAgent.
1175
+ * @todo: The httpHeaders part is not yet used.
1176
+ *
1177
+ * @param string $key
1178
+ * @param string $userAgent deprecated
1179
+ * @param string $httpHeaders deprecated
1180
+ * @return bool|int|null
1181
+ */
1182
+ public function is($key, $userAgent = null, $httpHeaders = null)
1183
+ {
1184
+ // Set the UA and HTTP headers only if needed (eg. batch mode).
1185
+ if ($httpHeaders) {
1186
+ $this->setHttpHeaders($httpHeaders);
1187
+ }
1188
+
1189
+ if ($userAgent) {
1190
+ $this->setUserAgent($userAgent);
1191
+ }
1192
+
1193
+ $this->setDetectionType(self::DETECTION_TYPE_EXTENDED);
1194
+
1195
+ return $this->matchUAAgainstKey($key);
1196
+ }
1197
+
1198
+ /**
1199
+ * Some detection rules are relative (not standard),
1200
+ * because of the diversity of devices, vendors and
1201
+ * their conventions in representing the User-Agent or
1202
+ * the HTTP headers.
1203
+ *
1204
+ * This method will be used to check custom regexes against
1205
+ * the User-Agent string.
1206
+ *
1207
+ * @param $regex
1208
+ * @param string $userAgent
1209
+ * @return bool
1210
+ *
1211
+ * @todo: search in the HTTP headers too.
1212
+ */
1213
+ public function match($regex, $userAgent = null)
1214
+ {
1215
+ $match = (bool) preg_match(sprintf('#%s#is', $regex), (false === empty($userAgent) ? $userAgent : $this->userAgent), $matches);
1216
+ // If positive match is found, store the results for debug.
1217
+ if ($match) {
1218
+ $this->matchingRegex = $regex;
1219
+ $this->matchesArray = $matches;
1220
+ }
1221
+
1222
+ return $match;
1223
+ }
1224
+
1225
+ /**
1226
+ * Get the properties array.
1227
+ *
1228
+ * @return array
1229
+ */
1230
+ public static function getProperties()
1231
+ {
1232
+ return self::$properties;
1233
+ }
1234
+
1235
+ /**
1236
+ * Prepare the version number.
1237
+ *
1238
+ * @todo Remove the error supression from str_replace() call.
1239
+ *
1240
+ * @param string $ver The string version, like "2.6.21.2152";
1241
+ *
1242
+ * @return float
1243
+ */
1244
+ public function prepareVersionNo($ver)
1245
+ {
1246
+ $ver = str_replace(array('_', ' ', '/'), '.', $ver);
1247
+ $arrVer = explode('.', $ver, 2);
1248
+
1249
+ if (isset($arrVer[1])) {
1250
+ $arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions.
1251
+ }
1252
+
1253
+ return (float) implode('.', $arrVer);
1254
+ }
1255
+
1256
+ /**
1257
+ * Check the version of the given property in the User-Agent.
1258
+ * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
1259
+ *
1260
+ * @param string $propertyName The name of the property. See self::getProperties() array
1261
+ * keys for all possible properties.
1262
+ * @param string $type Either self::VERSION_TYPE_STRING to get a string value or
1263
+ * self::VERSION_TYPE_FLOAT indicating a float value. This parameter
1264
+ * is optional and defaults to self::VERSION_TYPE_STRING. Passing an
1265
+ * invalid parameter will default to the this type as well.
1266
+ *
1267
+ * @return string|float The version of the property we are trying to extract.
1268
+ */
1269
+ public function version($propertyName, $type = self::VERSION_TYPE_STRING)
1270
+ {
1271
+ if (empty($propertyName)) {
1272
+ return false;
1273
+ }
1274
+
1275
+ // set the $type to the default if we don't recognize the type
1276
+ if ($type !== self::VERSION_TYPE_STRING && $type !== self::VERSION_TYPE_FLOAT) {
1277
+ $type = self::VERSION_TYPE_STRING;
1278
+ }
1279
+
1280
+ $properties = self::getProperties();
1281
+
1282
+ // Check if the property exists in the properties array.
1283
+ if (true === isset($properties[$propertyName])) {
1284
+
1285
+ // Prepare the pattern to be matched.
1286
+ // Make sure we always deal with an array (string is converted).
1287
+ $properties[$propertyName] = (array) $properties[$propertyName];
1288
+
1289
+ foreach ($properties[$propertyName] as $propertyMatchString) {
1290
+
1291
+ $propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString);
1292
+
1293
+ // Identify and extract the version.
1294
+ preg_match(sprintf('#%s#is', $propertyPattern), $this->userAgent, $match);
1295
+
1296
+ if (false === empty($match[1])) {
1297
+ $version = ($type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1]);
1298
+
1299
+ return $version;
1300
+ }
1301
+
1302
+ }
1303
+
1304
+ }
1305
+
1306
+ return false;
1307
+ }
1308
+
1309
+ /**
1310
+ * Retrieve the mobile grading, using self::MOBILE_GRADE_* constants.
1311
+ *
1312
+ * @return string One of the self::MOBILE_GRADE_* constants.
1313
+ */
1314
+ public function mobileGrade()
1315
+ {
1316
+ $isMobile = $this->isMobile();
1317
+
1318
+ if (
1319
+ // Apple iOS 4-7.0 – Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3 / 5.1 / 6.1), iPad 3 (5.1 / 6.0), iPad Mini (6.1), iPad Retina (7.0), iPhone 3GS (4.3), iPhone 4 (4.3 / 5.1), iPhone 4S (5.1 / 6.0), iPhone 5 (6.0), and iPhone 5S (7.0)
1320
+ $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) >= 4.3 ||
1321
+ $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) >= 4.3 ||
1322
+ $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) >= 4.3 ||
1323
+
1324
+ // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5)
1325
+ // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM
1326
+ // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices
1327
+ // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7
1328
+ ( $this->version('Android', self::VERSION_TYPE_FLOAT)>2.1 && $this->is('Webkit') ) ||
1329
+
1330
+ // Windows Phone 7.5-8 - Tested on the HTC Surround (7.5), HTC Trophy (7.5), LG-E900 (7.5), Nokia 800 (7.8), HTC Mazaa (7.8), Nokia Lumia 520 (8), Nokia Lumia 920 (8), HTC 8x (8)
1331
+ $this->version('Windows Phone OS', self::VERSION_TYPE_FLOAT) >= 7.5 ||
1332
+
1333
+ // Tested on the Torch 9800 (6) and Style 9670 (6), BlackBerry® Torch 9810 (7), BlackBerry Z10 (10)
1334
+ $this->is('BlackBerry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 6.0 ||
1335
+ // Blackberry Playbook (1.0-2.0) - Tested on PlayBook
1336
+ $this->match('Playbook.*Tablet') ||
1337
+
1338
+ // Palm WebOS (1.4-3.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0), HP TouchPad (3.0)
1339
+ ( $this->version('webOS', self::VERSION_TYPE_FLOAT) >= 1.4 && $this->match('Palm|Pre|Pixi') ) ||
1340
+ // Palm WebOS 3.0 - Tested on HP TouchPad
1341
+ $this->match('hp.*TouchPad') ||
1342
+
1343
+ // Firefox Mobile 18 - Tested on Android 2.3 and 4.1 devices
1344
+ ( $this->is('Firefox') && $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 18 ) ||
1345
+
1346
+ // Chrome for Android - Tested on Android 4.0, 4.1 device
1347
+ ( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 4.0 ) ||
1348
+
1349
+ // Skyfire 4.1 - Tested on Android 2.3 device
1350
+ ( $this->is('Skyfire') && $this->version('Skyfire', self::VERSION_TYPE_FLOAT) >= 4.1 && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) ||
1351
+
1352
+ // Opera Mobile 11.5-12: Tested on Android 2.3
1353
+ ( $this->is('Opera') && $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11.5 && $this->is('AndroidOS') ) ||
1354
+
1355
+ // Meego 1.2 - Tested on Nokia 950 and N9
1356
+ $this->is('MeeGoOS') ||
1357
+
1358
+ // Tizen (pre-release) - Tested on early hardware
1359
+ $this->is('Tizen') ||
1360
+
1361
+ // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser
1362
+ // @todo: more tests here!
1363
+ $this->is('Dolfin') && $this->version('Bada', self::VERSION_TYPE_FLOAT) >= 2.0 ||
1364
+
1365
+ // UC Browser - Tested on Android 2.3 device
1366
+ ( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) ||
1367
+
1368
+ // Kindle 3 and Fire - Tested on the built-in WebKit browser for each
1369
+ ( $this->match('Kindle Fire') ||
1370
+ $this->is('Kindle') && $this->version('Kindle', self::VERSION_TYPE_FLOAT) >= 3.0 ) ||
1371
+
1372
+ // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet
1373
+ $this->is('AndroidOS') && $this->is('NookTablet') ||
1374
+
1375
+ // Chrome Desktop 16-24 - Tested on OS X 10.7 and Windows 7
1376
+ $this->version('Chrome', self::VERSION_TYPE_FLOAT) >= 16 && !$isMobile ||
1377
+
1378
+ // Safari Desktop 5-6 - Tested on OS X 10.7 and Windows 7
1379
+ $this->version('Safari', self::VERSION_TYPE_FLOAT) >= 5.0 && !$isMobile ||
1380
+
1381
+ // Firefox Desktop 10-18 - Tested on OS X 10.7 and Windows 7
1382
+ $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 10.0 && !$isMobile ||
1383
+
1384
+ // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7
1385
+ $this->version('IE', self::VERSION_TYPE_FLOAT) >= 7.0 && !$isMobile ||
1386
+
1387
+ // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7
1388
+ $this->version('Opera', self::VERSION_TYPE_FLOAT) >= 10 && !$isMobile
1389
+ ){
1390
+ return self::MOBILE_GRADE_A;
1391
+ }
1392
+
1393
+ if (
1394
+ $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT)<4.3 ||
1395
+ $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<4.3 ||
1396
+ $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT)<4.3 ||
1397
+
1398
+ // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770
1399
+ $this->is('Blackberry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 5 && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<6 ||
1400
+
1401
+ //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3
1402
+ ($this->version('Opera Mini', self::VERSION_TYPE_FLOAT) >= 5.0 && $this->version('Opera Mini', self::VERSION_TYPE_FLOAT) <= 7.0 &&
1403
+ ($this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 || $this->is('iOS')) ) ||
1404
+
1405
+ // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1)
1406
+ $this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') ||
1407
+
1408
+ // @todo: report this (tested on Nokia N71)
1409
+ $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11 && $this->is('SymbianOS')
1410
+ ){
1411
+ return self::MOBILE_GRADE_B;
1412
+ }
1413
+
1414
+ if (
1415
+ // Blackberry 4.x - Tested on the Curve 8330
1416
+ $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) <= 5.0 ||
1417
+ // Windows Mobile - Tested on the HTC Leo (WinMo 5.2)
1418
+ $this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile', self::VERSION_TYPE_FLOAT) <= 5.2 ||
1419
+
1420
+ // Tested on original iPhone (3.1), iPhone 3 (3.2)
1421
+ $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) <= 3.2 ||
1422
+ $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) <= 3.2 ||
1423
+ $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) <= 3.2 ||
1424
+
1425
+ // Internet Explorer 7 and older - Tested on Windows XP
1426
+ $this->version('IE', self::VERSION_TYPE_FLOAT) <= 7.0 && !$isMobile
1427
+ ){
1428
+ return self::MOBILE_GRADE_C;
1429
+ }
1430
+
1431
+ // All older smartphone platforms and featurephones - Any device that doesn't support media queries
1432
+ // will receive the basic, C grade experience.
1433
+ return self::MOBILE_GRADE_C;
1434
+ }
1435
+ }
includes/classes/utils/Options.php ADDED
@@ -0,0 +1,430 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) exit;
3
+
4
+ class TCMP_Options {
5
+ public function __construct() {
6
+
7
+ }
8
+
9
+ //Cache
10
+ private function getCacheName($array) {
11
+ if(!is_array($array)) {
12
+ $array=array($array);
13
+ }
14
+ $result='Cache';
15
+ foreach($array as $v) {
16
+ if(is_object($v)) {
17
+ $v=get_class($v);
18
+ } elseif(is_array($v)) {
19
+ $v=$v[0];
20
+ if(is_object($v)) {
21
+ $v=get_class($v);
22
+ }
23
+ }
24
+ $result.='_'.$v;
25
+ }
26
+ return $result;
27
+ }
28
+ public function getCache($name, $callable=NULL) {
29
+ $key=$this->getCacheName($name);
30
+ $result=$this->getRequest($key, FALSE);
31
+ if($result===FALSE && $callable && is_callable($callable)) {
32
+ $result=$callable();
33
+ $this->setCache($name, $result);
34
+ }
35
+ return $result;
36
+ }
37
+ public function setCache($name, $value) {
38
+ $key=$this->getCacheName($name);
39
+ $this->setRequest($key, $value);
40
+ }
41
+
42
+ //always add a prefix to avoid conflicts with other plugins
43
+ private function getKey($key) {
44
+ return 'TCM_'.$key;
45
+ }
46
+ //option
47
+ private function removeOption($key) {
48
+ $key=$this->getKey($key);
49
+ delete_option($key);
50
+ }
51
+ private function getOption($key, $default=FALSE) {
52
+ $key=$this->getKey($key);
53
+ $result=get_option($key, $default);
54
+ if(is_string($result)) {
55
+ $result=trim($result);
56
+ }
57
+ return $result;
58
+ }
59
+ private function setOption($key, $value) {
60
+ $key=$this->getKey($key);
61
+ if(is_bool($value)) {
62
+ $value=($value ? 1 : 0);
63
+ }
64
+ update_option($key, $value);
65
+ }
66
+
67
+ //$_SESSION
68
+ private function removeSession($key) {
69
+ global $wp_session;
70
+
71
+ $key=$this->getKey($key);
72
+ if(isset($wp_session[$key])) {
73
+ unset($wp_session[$key]);
74
+ }
75
+ }
76
+ private function getSession($key, $default=FALSE) {
77
+ global $wp_session;
78
+
79
+ $key=$this->getKey($key);
80
+ $result=$default;
81
+ if(isset($wp_session[$key])) {
82
+ $result=$wp_session[$key];
83
+ }
84
+ if(is_string($result)) {
85
+ $result=trim($result);
86
+ }
87
+ return $result;
88
+ }
89
+ private function setSession($key, $value) {
90
+ global $wp_session;
91
+
92
+ $key=$this->getKey($key);
93
+ $wp_session[$key]=$value;
94
+ }
95
+
96
+ //$_REQUEST
97
+ //However WP enforces its own logic - during load process wp_magic_quotes() processes variables to emulate magic quotes setting and enforces $_REQUEST to contain combination of $_GET and $_POST, no matter what PHP configuration says.
98
+ private function removeRequest($key) {
99
+ $key=$this->getKey($key);
100
+ if(isset($_POST[$key])) {
101
+ unset($_POST[$key]);
102
+ }
103
+ }
104
+ private function getRequest($key, $default=FALSE) {
105
+ $key=$this->getKey($key);
106
+ $result=$default;
107
+ if(isset($_POST[$key])) {
108
+ $result=$_POST[$key];
109
+ }
110
+ return $result;
111
+ }
112
+ private function setRequest($key, $value) {
113
+ $key=$this->getKey($key);
114
+ $_POST[$key]=$value;
115
+ }
116
+
117
+ public function isPluginFirstInstall() {
118
+ return $this->getOption('PluginFirstInstall', FALSE);
119
+ }
120
+ public function setPluginFirstInstall($value) {
121
+ $this->setOption('PluginFirstInstall', $value);
122
+ }
123
+ public function isShowActivationNotice() {
124
+ return $this->getOption('ShowActivationNotice', FALSE);
125
+ }
126
+ public function setShowActivationNotice($value) {
127
+ $this->setOption('ShowActivationNotice', $value);
128
+ }
129
+
130
+ public function getShowWhatsNewSeenVersion() {
131
+ return intval($this->getOption('ShowWhatsNewSeenVersion', 0));
132
+ }
133
+ public function setShowWhatsNewSeenVersion($value) {
134
+ $this->setOption('ShowWhatsNewSeenVersion', $value);
135
+ }
136
+
137
+ //ShowWhatsNew
138
+ public function isShowWhatsNew() {
139
+ $result=intval($this->getOption('ShowWhatsNew', TRUE));
140
+ if($result) {
141
+ $v=$this->getShowWhatsNewSeenVersion();
142
+ if($v==TCMP_WHATSNEW_VERSION) {
143
+ $result=FALSE;
144
+ $this->getOption('ShowWhatsNew', FALSE);
145
+ }
146
+ }
147
+ return $result;
148
+ }
149
+ public function setShowWhatsNew($value) {
150
+ $this->setOption('ShowWhatsNew', $value);
151
+ }
152
+
153
+ //TrackingEnable
154
+ public function isTrackingEnable() {
155
+ return $this->getOption('TrackingEnable', 0);
156
+ }
157
+ public function setTrackingEnable($value) {
158
+ $this->setOption('TrackingEnable', $value);
159
+ }
160
+ //TrackingNotice
161
+ public function isTrackingNotice() {
162
+ return $this->getOption('TrackingNotice', 1);
163
+ }
164
+ public function setTrackingNotice($value) {
165
+ $this->setOption('TrackingNotice', $value);
166
+ }
167
+
168
+ public function getTrackingLastSend() {
169
+ return $this->getOption('TrackingLastSend['.TCMP_PLUGIN_SLUG.']', 0);
170
+ }
171
+ public function setTrackingLastSend($value) {
172
+ $this->setOption('TrackingLastSend['.TCMP_PLUGIN_SLUG.']', $value);
173
+ }
174
+ public function getPluginInstallDate() {
175
+ return $this->getOption('PluginInstallDate['.TCMP_PLUGIN_SLUG.']', 0);
176
+ }
177
+ public function setPluginInstallDate($value) {
178
+ $this->setOption('PluginInstallDate['.TCMP_PLUGIN_SLUG.']', $value);
179
+ }
180
+ public function getPluginUpdateDate() {
181
+ return $this->getOption('PluginUpdateDate['.TCMP_PLUGIN_SLUG.']', 0);
182
+ }
183
+ public function setPluginUpdateDate($value) {
184
+ $this->setOption('PluginUpdateDate['.TCMP_PLUGIN_SLUG.']', $value);
185
+ }
186
+
187
+ //LicenseKey
188
+ public function getLicenseKey() {
189
+ return $this->getOption('LiceseKey', '');
190
+ }
191
+ public function setLicenseKey($value) {
192
+ $this->setOption('LiceseKey', $value);
193
+ }
194
+ //LicenseStatus
195
+ public function isLicenseSuccess() {
196
+ return $this->getOption('LicenseSuccess', 0);
197
+ }
198
+ public function setLicenseSuccess($value) {
199
+ $this->setOption('LicenseSuccess', $value);
200
+ }
201
+ //License
202
+ public function getLicense() {
203
+ return $this->getOption('License', FALSE);
204
+ }
205
+ public function setLicense($value) {
206
+ $this->setOption('License', $value);
207
+ }
208
+ //LicenseSiteCount
209
+ public function getLicenseSiteCount() {
210
+ return $this->getOption('LicenseSiteCount', FALSE);
211
+ }
212
+ public function setLicenseSiteCount($value) {
213
+ $this->setOption('LicenseSiteCount', $value);
214
+ }
215
+ //LicenseLastCheck
216
+ public function getLicenseLastCheck() {
217
+ return intval($this->getOption('LicenseLastCheck', 0));
218
+ }
219
+ public function setLicenseLastCheck($value) {
220
+ $this->setOption('LicenseLastCheck', intval($value));
221
+ }
222
+
223
+ //LoggerEnable
224
+ public function isLoggerEnable() {
225
+ return ($this->getOption('LoggerEnable', FALSE) || (defined('TCMP_LOGGER') && TCMP_LOGGER));
226
+ }
227
+ public function setLoggerEnable($value) {
228
+ $this->setOption('LoggerEnable', $value);
229
+ }
230
+
231
+ //Snippet
232
+ public function getSnippet($id) {
233
+ return $this->getOption('Snippet_'.$id, NULL);
234
+ }
235
+ public function setSnippet($id, $value) {
236
+ $this->setOption('Snippet_'.$id, $value);
237
+ }
238
+ public function removeSnippet($id) {
239
+ $this->removeOption('Snippet_'.$id);
240
+ }
241
+ //SnippetList
242
+ public function getSnippetList() {
243
+ return $this->getOption('SnippetList', array());
244
+ }
245
+ public function setSnippetList($value) {
246
+ $this->setOption('SnippetList', $value);
247
+ }
248
+ public function removeSnippetList() {
249
+ $this->removeOption('SnippetList');
250
+ }
251
+
252
+ public function pushConversionSnippets($options, TCMP_EcommercePurchase $purchase) {
253
+ global $tcmp;
254
+ $this->setRequest('EcommercePurchase', $purchase);
255
+ $snippets=$tcmp->Manager->getConversionSnippets($options);
256
+ foreach($snippets as $v) {
257
+ $id=$v['id'];
258
+ $tcmp->Options->pushConversionSnippetId($id);
259
+ }
260
+ }
261
+ public function pushConversionSnippetId($id) {
262
+ $array=$this->getRequest('ConversionSnippetIds', array());
263
+ $array[]=$id;
264
+ $array=array_unique($array);
265
+ $this->setRequest('ConversionSnippetIds', $array);
266
+ }
267
+ public function getConversionSnippetIds() {
268
+ return $this->getRequest('ConversionSnippetIds', FALSE);
269
+ }
270
+ public function getEcommercePurchase() {
271
+ /* @var $result TCMP_EcommercePurchase */
272
+ $result=$this->getRequest('EcommercePurchase', FALSE);
273
+ return $result;
274
+ }
275
+
276
+ public function hasSnippetWritten($snippet) {
277
+ //check also the md5 of code so if the user create 2 different snippets with
278
+ //the same tracking code we will not insert into 2 times inside the html
279
+ $id=$snippet['id'];
280
+ $md5=md5($snippet['code']);
281
+
282
+ $listIds=$this->getRequest('SnippetsWrittenIds', array());
283
+ $listMd5=$this->getRequest('SnippetsWrittenMd5', array());
284
+
285
+ $result=(in_array($id, $listIds) || in_array($md5, $listMd5));
286
+ return $result;
287
+ }
288
+ public function pushSnippetWritten($snippet) {
289
+ $md5=md5($snippet['code']);
290
+ $id=$snippet['id'];
291
+ $listIds=$this->getRequest('SnippetsWrittenIds', array());
292
+ $listMd5=$this->getRequest('SnippetsWrittenMd5', array());
293
+
294
+ $listIds[$id]=$snippet;
295
+ $listMd5[$md5]=$id;
296
+ $this->setRequest('SnippetsWrittenIds', $listIds);
297
+ $this->setRequest('SnippetsWrittenMd5', $listMd5);
298
+ }
299
+ public function getSnippetsWritten() {
300
+ return $this->getRequest('SnippetsWrittenIds', array());
301
+ }
302
+ public function clearSnippetsWritten() {
303
+ $this->setRequest('SnippetsWrittenIds', array());
304
+ $this->setRequest('SnippetsWrittenMd5', array());
305
+ }
306
+
307
+ //PostShown
308
+ public function getPostShown() {
309
+ return $this->getRequest('PostShown');
310
+ }
311
+ public function setPostShown($post) {
312
+ $this->setRequest('PostShown', $post);
313
+ }
314
+
315
+ private function hasGenericMessages($type) {
316
+ $result=$this->getRequest($type.'Messages', NULL);
317
+ return (is_array($result) && count($result)>0);
318
+ }
319
+ private function pushGenericMessage($type, $message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
320
+ global $tcmp;
321
+ $array=$this->getRequest($type.'Messages', array());
322
+ $array[]=$tcmp->Lang->L($message, $v1, $v2, $v3, $v4, $v5);
323
+ $this->setRequest($type.'Messages', $array);
324
+ }
325
+ private function writeGenericMessages($type, $clean=TRUE) {
326
+ $result=FALSE;
327
+ $array=$this->getRequest($type.'Messages', array());
328
+ if(is_array($array) && count($array)>0) {
329
+ $result=TRUE;
330
+ ?>
331
+ <div class="tcmp-box-<?php echo strtolower($type)?>"><?php echo wpautop(implode("\n", $array)); ?></div>
332
+ <?php }
333
+ if($clean) {
334
+ $this->removeRequest($type.'Messages');
335
+ }
336
+ return $result;
337
+ }
338
+
339
+ //WarningMessages
340
+ public function hasWarningMessages() {
341
+ return $this->hasGenericMessages('Warning');
342
+ }
343
+ public function pushWarningMessage($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
344
+ return $this->pushGenericMessage('Warning', $message, $v1, $v2, $v3, $v4, $v5);
345
+ }
346
+ public function writeWarningMessages($clean=TRUE) {
347
+ return $this->writeGenericMessages('Warning', $clean);
348
+ }
349
+ //SuccessMessages
350
+ public function hasSuccessMessages() {
351
+ return $this->hasGenericMessages('Success');
352
+ }
353
+ public function pushSuccessMessage($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
354
+ return $this->pushGenericMessage('Success', $message, $v1, $v2, $v3, $v4, $v5);
355
+ }
356
+ public function writeSuccessMessages($clean=TRUE) {
357
+ return $this->writeGenericMessages('Success', $clean);
358
+ }
359
+ //InfoMessages
360
+ public function hasInfoMessages() {
361
+ return $this->hasGenericMessages('Info');
362
+ }
363
+ public function pushInfoMessage($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
364
+ return $this->pushGenericMessage('Info', $message, $v1, $v2, $v3, $v4, $v5);
365
+ }
366
+ public function writeInfoMessages($clean=TRUE) {
367
+ return $this->writeGenericMessages('Info', $clean);
368
+ }
369
+ //ErrorMessages
370
+ public function hasErrorMessages() {
371
+ return $this->hasGenericMessages('Error');
372
+ }
373
+ public function pushErrorMessage($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
374
+ return $this->pushGenericMessage('Error', $message, $v1, $v2, $v3, $v4, $v5);
375
+ }
376
+ public function writeErrorMessages($clean=TRUE) {
377
+ return $this->writeGenericMessages('Error', $clean);
378
+ }
379
+
380
+ public function writeMessages($clean=TRUE) {
381
+ $result=FALSE;
382
+ if($this->writeInfoMessages($clean)) {
383
+ $result=TRUE;
384
+ }
385
+ if($this->writeSuccessMessages($clean)) {
386
+ $result=TRUE;
387
+ }
388
+ if($this->writeWarningMessages($clean)) {
389
+ $result=TRUE;
390
+ }
391
+ if($this->writeErrorMessages($clean)) {
392
+ $result=TRUE;
393
+ }
394
+
395
+ return $result;
396
+ }
397
+ public function pushMessage($success, $message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
398
+ if($success) {
399
+ $this->pushSuccessMessage($message.'Success', $v1, $v2, $v3, $v4, $v5);
400
+ } else {
401
+ $this->pushErrorMessage($message.'Error', $v1, $v2, $v3, $v4, $v5);
402
+ }
403
+ }
404
+
405
+ public function getFeedbackEmail() {
406
+ return $this->getOption('FeedbackEmail', get_bloginfo('admin_email'));
407
+ }
408
+ public function setFeedbackEmail($value) {
409
+ $this->setOption('FeedbackEmail', $value);
410
+ }
411
+
412
+ //MetaboxPostTypes
413
+ public function getMetaboxPostTypes($create=TRUE) {
414
+ global $tcmp;
415
+ $result=$this->getOption('MetaboxPostTypes', array());
416
+ if($create) {
417
+ $types=$tcmp->Utils->query(TCMP_QUERY_POST_TYPES);
418
+ foreach($types as $v) {
419
+ $v=$v['id'];
420
+ if(!isset($result[$v])) {
421
+ $result[$v]=(in_array($v, array('post', 'page')) ? 1 : 0);
422
+ }
423
+ }
424
+ }
425
+ return $result;
426
+ }
427
+ public function setMetaboxPostTypes($values) {
428
+ $this->setOption('MetaboxPostTypes', $values);
429
+ }
430
+ }
includes/classes/utils/Plugin.php ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ define('TCMP_PLUGINS_NO_PLUGINS', 10000);
5
+ define('TCMP_PLUGINS_WOOCOMMERCE', 10001);
6
+ define('TCMP_PLUGINS_EDD', 10002);
7
+ define('TCMP_PLUGINS_WP_ECOMMERCE', 10003);
8
+ define('TCMP_PLUGINS_WP_SPSC', 10004);
9
+ define('TCMP_PLUGINS_S2MEMBER', 10005);
10
+ define('TCMP_PLUGINS_MEMBERS', 10006);
11
+ define('TCMP_PLUGINS_CART66', 10007);
12
+ define('TCMP_PLUGINS_ESHOP', 10008);
13
+ define('TCMP_PLUGINS_JIGOSHOP', 10009);
14
+ define('TCMP_PLUGINS_MARKETPRESS', 10010);
15
+ define('TCMP_PLUGINS_SHOPP', 10011);
16
+ define('TCMP_PLUGINS_SIMPLE_WP_ECOMMERCE', 10012);
17
+ define('TCMP_PLUGINS_CF7', 10013);
18
+ define('TCMP_PLUGINS_GRAVITY', 10014);
19
+ define('TCMP_PLUGINS_TRACKING_CODE_MANAGER', 10015);
20
+ define('TCMP_PLUGINS_TRACKING_CODE_MANAGER_PRO', 10016);
21
+
22
+ class TCMP_Plugin {
23
+ function __construct() {
24
+ }
25
+
26
+ function getName($pluginId) {
27
+ $result='';
28
+ switch ($pluginId) {
29
+ case TCMP_PLUGINS_WOOCOMMERCE:
30
+ $result='WooCommerce';
31
+ break;
32
+ case TCMP_PLUGINS_EDD:
33
+ $result='Easy Digital Download';
34
+ break;
35
+ case TCMP_PLUGINS_WP_ECOMMERCE:
36
+ $result='WP eCommerce';
37
+ break;
38
+ case TCMP_PLUGINS_WP_SPSC:
39
+ $result='WordPress Simple Paypal Shopping Cart';
40
+ break;
41
+ case TCMP_PLUGINS_S2MEMBER:
42
+ $result='s2member';
43
+ break;
44
+ case TCMP_PLUGINS_MEMBERS:
45
+ $result='Members';
46
+ break;
47
+ case TCMP_PLUGINS_CART66:
48
+ $result='Cart66 Lite :: WordPress Ecommerce';
49
+ break;
50
+ case TCMP_PLUGINS_ESHOP:
51
+ $result='eShop';
52
+ break;
53
+ case TCMP_PLUGINS_JIGOSHOP:
54
+ $result='Jigoshop';
55
+ break;
56
+ case TCMP_PLUGINS_MARKETPRESS:
57
+ $result='MarketPress - WordPress eCommerce';
58
+ break;
59
+ case TCMP_PLUGINS_SHOPP:
60
+ $result='Shopp';
61
+ break;
62
+ case TCMP_PLUGINS_SIMPLE_WP_ECOMMERCE:
63
+ $result='iThemes Exchange: Simple WP Ecommerce';
64
+ break;
65
+ case TCMP_PLUGINS_CF7:
66
+ $result='Contact Form 7';
67
+ break;
68
+ case TCMP_PLUGINS_GRAVITY:
69
+ $result='Gravity Form';
70
+ break;
71
+ case TCMP_PLUGINS_TRACKING_CODE_MANAGER:
72
+ $result='Tracking Code Manager';
73
+ break;
74
+ case TCMP_PLUGINS_TRACKING_CODE_MANAGER_PRO:
75
+ $result='Tracking Code Manager PRO';
76
+ break;
77
+ }
78
+ return $result;
79
+ }
80
+ function isActive($pluginId) {
81
+ global $tcmp;
82
+
83
+ $php='';
84
+ $class='';
85
+ $constant='';
86
+ switch ($pluginId) {
87
+ case TCMP_PLUGINS_WOOCOMMERCE:
88
+ $php='woocommerce/woocommerce.php';
89
+ $class='WooCommerce';
90
+ $constant='WOOCOMMERCE_VERSION';
91
+ break;
92
+ case TCMP_PLUGINS_EDD:
93
+ $php='easy-digital-downloads/easy-digital-downloads.php';
94
+ $class='Easy_Digital_Downloads';
95
+ $constant='EDD_SL_VERSION';
96
+ break;
97
+ case TCMP_PLUGINS_WP_ECOMMERCE:
98
+ $class='WP_eCommerce';
99
+ $constant='WPSC_VERSION';
100
+ break;
101
+ case TCMP_PLUGINS_WP_SPSC:
102
+ $constant='WP_CART_VERSION';
103
+ break;
104
+ case TCMP_PLUGINS_S2MEMBER:
105
+ $constant='WS_PLUGIN__S2MEMBER_VERSION';
106
+ break;
107
+ case TCMP_PLUGINS_MEMBERS:
108
+ $constant='MEMBERS_VERSION';
109
+ break;
110
+ case TCMP_PLUGINS_CART66:
111
+ $class='Cart66';
112
+ $constant='CART66_VERSION_NUMBER';
113
+ break;
114
+ case TCMP_PLUGINS_ESHOP:
115
+ $constant='ESHOP_VERSION';
116
+ break;
117
+ case TCMP_PLUGINS_JIGOSHOP:
118
+ $constant='JIGOSHOP_VERSION';
119
+ break;
120
+ case TCMP_PLUGINS_MARKETPRESS:
121
+ $class='MarketPress';
122
+ $constant='MP_LITE';
123
+ break;
124
+ case TCMP_PLUGINS_SHOPP:
125
+ $constant='ESHOP_VERSION';
126
+ break;
127
+ case TCMP_PLUGINS_SIMPLE_WP_ECOMMERCE:
128
+ $class='IT_Exchange';
129
+ $constant='';
130
+ break;
131
+ case TCMP_PLUGINS_CF7:
132
+ $constant='WPCF7_VERSION';
133
+ break;
134
+ case TCMP_PLUGINS_GRAVITY:
135
+ $constant='';
136
+ break;
137
+ case TCMP_PLUGINS_TRACKING_CODE_MANAGER:
138
+ $constant='TCMP_PLUGIN_VERSION';
139
+ break;
140
+ case TCMP_PLUGINS_TRACKING_CODE_MANAGER_PRO:
141
+ $constant='TCMP_PLUGIN_VERSION';
142
+ break;
143
+ }
144
+ $result=$this->isPluginActive($class, $constant, $php);
145
+ return $result;
146
+ }
147
+
148
+ private function isPluginActive($class='', $constant='', $plugin='') {
149
+ $result=FALSE;
150
+ $result=($result || ($class!='' && class_exists($class)));
151
+ $result=($result || ($constant!='' && defined($constant)));
152
+ //require plugin.php
153
+ //$result=($result || ($plugin!='' && is_plugin_active($plugin)));
154
+ return $result;
155
+ }
156
+
157
+ function getVersion($pluginId) {
158
+ $constant='';
159
+ $version='';
160
+ switch ($pluginId) {
161
+ case TCMP_PLUGINS_WOOCOMMERCE:
162
+ $constant='WOOCOMMERCE_VERSION';
163
+ break;
164
+ case TCMP_PLUGINS_EDD:
165
+ $constant='EDD_SL_VERSION';
166
+ break;
167
+ case TCMP_PLUGINS_WP_ECOMMERCE:
168
+ $constant='WPSC_VERSION';
169
+ break;
170
+ case TCMP_PLUGINS_WP_SPSC:
171
+ $constant='WP_CART_VERSION';
172
+ break;
173
+ case TCMP_PLUGINS_S2MEMBER:
174
+ $constant='WS_PLUGIN__S2MEMBER_VERSION';
175
+ break;
176
+ case TCMP_PLUGINS_MEMBERS:
177
+ $constant='MEMBERS_VERSION';
178
+ break;
179
+ case TCMP_PLUGINS_CART66:
180
+ $constant='CART66_VERSION_NUMBER';
181
+ break;
182
+ case TCMP_PLUGINS_ESHOP:
183
+ $constant='ESHOP_VERSION';
184
+ break;
185
+ case TCMP_PLUGINS_JIGOSHOP:
186
+ $constant='JIGOSHOP_VERSION';
187
+ break;
188
+ case TCMP_PLUGINS_MARKETPRESS:
189
+ global $mp;
190
+ $version=$mp->version;
191
+ break;
192
+ case TCMP_PLUGINS_SHOPP:
193
+ $constant='ESHOP_VERSION';
194
+ break;
195
+ case TCMP_PLUGINS_SIMPLE_WP_ECOMMERCE:
196
+ $version=$GLOBALS['it_exchange']['version'];
197
+ break;
198
+ case TCMP_PLUGINS_CF7:
199
+ $constant='WPCF7_VERSION';
200
+ break;
201
+ case TCMP_PLUGINS_GRAVITY:
202
+ $constant='';
203
+ break;
204
+ }
205
+ if($version=='' && $constant!='') {
206
+ $version=(defined($constant) ? constant($constant) : '');
207
+ }
208
+ return $version;
209
+ }
210
+
211
+ function getActivePlugins($ids) {
212
+ return $this->getActivePlugins($ids, TRUE);
213
+ }
214
+ function getPlugins($ids, $onlyActive=TRUE) {
215
+ $array=array();
216
+ if(!is_array($ids)) {
217
+ $ids=array(intval($ids));
218
+ }
219
+
220
+ foreach($ids as $id) {
221
+ if(!$onlyActive || $this->isActive($id)) {
222
+ $name=$this->getName($id);
223
+ $version=$this->getVersion($id);
224
+
225
+ $v=array(
226
+ 'id'=>$id
227
+ , 'name'=>$name
228
+ , 'version'=>$version
229
+ , 'active'=>$this->isActive($id)
230
+ );
231
+ $array[$name]=$v;
232
+ }
233
+ }
234
+ ksort($array);
235
+ return $array;
236
+ }
237
+ }
includes/classes/utils/Properties.php ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ class TCMP_Properties {
5
+ var $data;
6
+ var $autoPush;
7
+
8
+ function __construct() {
9
+ $this->data=array();
10
+ $this->autoPush=TRUE;
11
+ }
12
+
13
+ public function hasKeys() {
14
+ return (count($this->data)>0);
15
+ }
16
+ public function existsKey($key) {
17
+ return (isset($this->data[$key]) && $this->data[$key]!='');
18
+ }
19
+
20
+ public function load($file) {
21
+ $bundle=array();
22
+ if(!file_exists($file)) {
23
+ return $bundle;
24
+ }
25
+ $file=file_get_contents($file);
26
+ if($file!=NULL && strlen($file)>0) {
27
+ $file=str_replace("\r\n", "\n", $file);
28
+ $file=str_replace("\n\n", "\n", $file);
29
+ $file=explode("\n", $file);
30
+
31
+ foreach($file as $row) {
32
+ $index=strpos($row, "=");
33
+ if($index===FALSE) continue;
34
+
35
+ $k=trim(substr($row, 0, $index));
36
+ $v=trim(substr($row, $index+1));
37
+ if($v!='') {
38
+ $bundle[$k]=$v;
39
+ }
40
+ }
41
+ }
42
+ $this->data=$bundle;
43
+ return $bundle;
44
+ }
45
+ public function store($file) {
46
+ ksort($this->data);
47
+ $buffer='';
48
+ foreach($this->data as $k=>$v) {
49
+ if($buffer!='') {
50
+ $buffer.="\r\n";
51
+ }
52
+ $buffer.=$k.'='.$v;
53
+ }
54
+ $bytes=file_put_contents($file, $buffer);
55
+ return ($bytes>0);
56
+ }
57
+
58
+ public function pushValue($t, $k, $v) {
59
+ $v=$this->encode($t, $v);
60
+ $this->data[$k]=$v;
61
+ }
62
+ public function pushString($k, $v) {
63
+ $this->pushValue('s', $k, $v);
64
+ }
65
+ public function pushBoolean($k, $v) {
66
+ $this->pushValue('b', $k, $v);
67
+ }
68
+ public function pushInt($k, $v) {
69
+ $this->pushValue('i', $k, $v);
70
+ }
71
+ public function pushFloat($k, $v) {
72
+ $this->pushValue('f', $k, $v);
73
+ }
74
+ public function pushDate($k, $v) {
75
+ $this->pushValue('d', $k, $v);
76
+ }
77
+ public function pushArray($k, $v) {
78
+ $this->pushValue('a', $k, $v);
79
+ }
80
+ public function pushAssocArray($k, $v) {
81
+ $this->pushValue('aa', $k, $v);
82
+ }
83
+
84
+ private function encode($t, $v) {
85
+ global $tcmp;
86
+ switch (strtolower($t)) {
87
+ case 's':
88
+ break;
89
+ case 'i':
90
+ $v=intval($v);
91
+ break;
92
+ case 'f':
93
+ $v=round(floatval($v), 2);
94
+ break;
95
+ case 'd':
96
+ $v=$tcmp->Utils->formatDatetime($v);
97
+ break;
98
+ case 'b':
99
+ $v=($tcmp->Utils->isTrue($v) ? 'true' : 'false');
100
+ break;
101
+ case 'a':
102
+ $v=$tcmp->Utils->toArray($v);
103
+ $v=implode('|', $v);
104
+ break;
105
+ case 'aa':
106
+ $array=$tcmp->Utils->toArray($v);
107
+ $buffer='';
108
+ foreach($array as $k=>$v) {
109
+ if($buffer!='') {
110
+ $buffer.='|';
111
+ }
112
+ $buffer.=$k.'='.$v;
113
+ }
114
+ $v=$array;
115
+ break;
116
+ }
117
+ return $v;
118
+ }
119
+ private function decode($t, $v) {
120
+ global $tcmp;
121
+ $v=trim($v);
122
+ switch (strtolower($t)) {
123
+ case 's':
124
+ break;
125
+ case 'i':
126
+ $v=intval($v);
127
+ break;
128
+ case 'f':
129
+ $v=round(floatval($v), 2);
130
+ break;
131
+ case 'd':
132
+ $v=$tcmp->Utils->parseDateToTime($v);
133
+ break;
134
+ case 'b':
135
+ $v=$tcmp->Utils->isTrue($v);
136
+ break;
137
+ case 'a':
138
+ $v=$tcmp->Utils->toArray($v);
139
+ break;
140
+ case 'aa':
141
+ $v=$tcmp->Utils->toArray($v);
142
+ $array=implode('|', $v);
143
+ $t=array();
144
+ foreach($array as $v) {
145
+ $v=explode('=', $v);
146
+ if(count($v)==1) {
147
+ $v[]='';
148
+ }
149
+ $t[trim($v[0])]=trim($v[1]);
150
+ }
151
+ $v=$t;
152
+ break;
153
+ }
154
+ return $v;
155
+ }
156
+
157
+ protected function getValue($t, $key, $default) {
158
+ $v=$default;
159
+ if(isset($this->data[$key])) {
160
+ $v=$this->data[$key];
161
+ } elseif($this->autoPush) {
162
+ $this->pushValue($t, $key, $default);
163
+ }
164
+ $v=$this->decode($t, $v);
165
+ return $v;
166
+ }
167
+ public function getString($key, $default='') {
168
+ return $this->getValue('s', $key, $default);
169
+ }
170
+ public function getFile($key, $default=FALSE) {
171
+ global $tcmp;
172
+ $file=$this->getString($key, $default);
173
+ if($file!==$default && $file!=='' && $file!==FALSE) {
174
+ if(!file_exists($file)) {
175
+ $file=$default;
176
+ }
177
+ }
178
+ if(is_dir($file)) {
179
+ $file=str_replace("\\", DIRECTORY_SEPARATOR, $file);
180
+ $file=str_replace("/", DIRECTORY_SEPARATOR, $file);
181
+ if(!$tcmp->Utils->endsWith($file, DIRECTORY_SEPARATOR)) {
182
+ $file.=DIRECTORY_SEPARATOR;
183
+ }
184
+ }
185
+ return $file;
186
+ }
187
+ public function getInt($key, $default=0) {
188
+ return $this->getValue('i', $key, $default);
189
+ }
190
+ public function getFloat($key, $default=0) {
191
+ return $this->getValue('f', $key, $default);
192
+ }
193
+ public function getBoolean($key, $default=FALSE) {
194
+ return $this->getValue('b', $key, $default);
195
+ }
196
+ public function getDate($key, $default=FALSE) {
197
+ return $this->getValue('d', $key, $default);
198
+ }
199
+ public function getArray($key, $default=FALSE) {
200
+ return $this->getValue('a', $key, $default);
201
+ }
202
+ public function getAssocArray($key, $default=FALSE) {
203
+ return $this->getValue('aa', $key, $default);
204
+ }
205
+ }
includes/{class-TCM-tracking.php → classes/utils/Tracking.php} RENAMED
@@ -10,15 +10,15 @@ if (!defined('ABSPATH')) exit;
10
  * @since 1.8.2
11
  * @return void
12
  */
13
- class TCM_Tracking {
14
 
15
  public function __construct() {
16
  //We send once a week (while tracking is allowed) to check in which can be used
17
  //to determine active sites
18
- add_action('tcm_weekly_scheduled_events', array($this, 'sendTracking'));
19
 
20
- //add_action('tcm_tracking_on', array($this, 'enableTracking'));
21
- //add_action('tcm_tracking_off', array($this, 'disableTracking'));
22
  //add_action('admin_notices', array($this, 'admin_notice'));
23
  }
24
 
@@ -57,7 +57,7 @@ class TCM_Tracking {
57
  $active_plugin = get_option( 'active_plugins' );
58
  foreach ( $active_plugin as $plugin_path ) {
59
  if ( ! function_exists( 'get_plugin_data' ) ) {
60
- require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
61
  }
62
 
63
  $plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin_path );
@@ -76,7 +76,7 @@ class TCM_Tracking {
76
  }
77
  //obtain tracking data into an associative array
78
  public function getData() {
79
- global $tcm;
80
 
81
  //retrieve blog info
82
  $result['wp_url']=home_url();
@@ -89,34 +89,36 @@ class TCM_Tracking {
89
  $result['theme']=$this->getThemeData();
90
 
91
  //to obtain for each post type its count
92
- $post_types=$tcm->Utils->query(TCM_QUERY_POST_TYPES);
93
  $data=array();
94
  foreach ($post_types as $v) {
95
- $v=$v['name'];
96
  $data[$v]=intval(wp_count_posts($v)->publish);
97
  }
98
  $result['post_types']=$data;
99
 
100
  //plugin configuration without secret-code
101
  $data=array();
102
- $keys=$tcm->Manager->keys();
103
  foreach($keys as $k) {
104
- $v=$tcm->Manager->get($k);
105
  //to allow us to receive a part of the code and to protect user privacy
106
  //we use this data only to know which SaaS services are used
107
  //and not to use your data
108
  $v['code']=substr($v['code'], 0, 100);
109
  $data[]=$v;
110
  }
111
- $result['iwpm_plugin_name']=TCM_PLUGIN_NAME;
112
- $result['iwpm_plugin_version']=TCM_PLUGIN_VERSION;
113
  $result['iwpm_plugin_data']=$data;
114
- $result['iwpm_plugin_install_date']=$tcm->Options->getPluginInstallDate();
115
- $result['iwpm_plugin_update_date']=$tcm->Options->getPluginUpdateDate();
116
 
117
- $result['iwpm_tracking_enable']=$tcm->Options->isTrackingEnable();
118
- $result['iwpm_logger_enable']=$tcm->Options->isLoggerEnable();
119
- $result['iwpm_feedback_email']=$tcm->Options->getFeedbackEmail();
 
 
120
 
121
  //var_dump($result);
122
  return $result;
@@ -124,14 +126,14 @@ class TCM_Tracking {
124
 
125
  //send tracking data info to our server
126
  public function sendTracking($override = FALSE) {
127
- global $tcm;
128
 
129
  $result=-1;
130
- if(!$override && !$tcm->Options->isTrackingEnable())
131
  return $result;
132
 
133
  // Send a maximum of once per week
134
- $last_send=$tcm->Options->getTrackingLastSend();
135
  if(!$override && $last_send>strtotime('-1 week'))
136
  return $result;
137
 
@@ -139,53 +141,26 @@ class TCM_Tracking {
139
  //add_filter('https_ssl_verify', '__return_false');
140
  //add_filter('block_local_requests', '__return_false');
141
 
142
- $data=$tcm->Utils->remotePost('usage', $this->getData());
143
  if($data) {
144
  $result=intval($data['id']);
145
- $tcm->Options->setTrackingLastSend(time());
146
  }
147
  return $result;
148
  }
149
 
150
  public function enableTracking() {
151
- global $tcm;
152
 
153
- $tcm->Options->setTrackingEnable(TRUE);
154
- $tcm->Options->setTrackingNotice(FALSE);
155
  $this->sendTracking(TRUE);
156
  }
157
  public function disableTracking() {
158
- global $tcm;
159
 
160
- $tcm->Options->setTrackingEnable(FALSE);
161
- $tcm->Options->setTrackingNotice(FALSE);
162
  $this->sendTracking(TRUE);
163
  }
164
-
165
- public function admin_notice() {
166
- global $tcm;
167
-
168
- if(!$tcm->Options->isTrackingNotice() || $tcm->Options->isTrackingEnable() || !current_user_can('manage_options'))
169
- return;
170
-
171
- if(FALSE && (
172
- stristr(network_site_url('/'), 'dev' ) !== false ||
173
- stristr(network_site_url('/'), 'localhost') !== false ||
174
- stristr(network_site_url('/'), ':8888' ) !== false // This is common with MAMP on OS X
175
- )) {
176
- $tcm->Options->setTrackingNotice(TRUE);
177
- } else {
178
- $yes_url=add_query_arg('tcm_action', 'manager_trackingOn');
179
- $no_url=add_query_arg('tcm_action', 'manager_trackingOff');
180
-
181
- ?>
182
- <div class="updated">
183
- <p>
184
- <?php $tcm->Lang->P('Allow IntellyWP to track plugin usage?');?>
185
- &nbsp;<a href="<?php echo esc_url($yes_url)?>" class="button-primary"><?php $tcm->Lang->P('Oh yes :)')?></a>
186
- &nbsp;<a href="<?php echo esc_url($no_url)?>" class="button-secondary"><?php $tcm->Lang->P('Refuse!')?></a>
187
- </p>
188
- </div>
189
- <?php }
190
- }
191
  }
10
  * @since 1.8.2
11
  * @return void
12
  */
13
+ class TCMP_Tracking {
14
 
15
  public function __construct() {
16
  //We send once a week (while tracking is allowed) to check in which can be used
17
  //to determine active sites
18
+ add_action('tcmp_weekly_scheduled_events', array($this, 'sendTracking'));
19
 
20
+ //add_action('tcmp_tracking_on', array($this, 'enableTracking'));
21
+ //add_action('tcmp_tracking_off', array($this, 'disableTracking'));
22
  //add_action('admin_notices', array($this, 'admin_notice'));
23
  }
24
 
57
  $active_plugin = get_option( 'active_plugins' );
58
  foreach ( $active_plugin as $plugin_path ) {
59
  if ( ! function_exists( 'get_plugin_data' ) ) {
60
+ require_once(ABSPATH . 'wp-admin/includes/plugin.php');
61
  }
62
 
63
  $plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin_path );
76
  }
77
  //obtain tracking data into an associative array
78
  public function getData() {
79
+ global $tcmp;
80
 
81
  //retrieve blog info
82
  $result['wp_url']=home_url();
89
  $result['theme']=$this->getThemeData();
90
 
91
  //to obtain for each post type its count
92
+ $post_types=$tcmp->Utils->query(TCMP_QUERY_POST_TYPES);
93
  $data=array();
94
  foreach ($post_types as $v) {
95
+ $v=$v['id'];
96
  $data[$v]=intval(wp_count_posts($v)->publish);
97
  }
98
  $result['post_types']=$data;
99
 
100
  //plugin configuration without secret-code
101
  $data=array();
102
+ $keys=$tcmp->Manager->keys();
103
  foreach($keys as $k) {
104
+ $v=$tcmp->Manager->get($k);
105
  //to allow us to receive a part of the code and to protect user privacy
106
  //we use this data only to know which SaaS services are used
107
  //and not to use your data
108
  $v['code']=substr($v['code'], 0, 100);
109
  $data[]=$v;
110
  }
111
+ $result['iwpm_plugin_name']=TCMP_PLUGIN_SLUG;
112
+ $result['iwpm_plugin_version']=TCMP_PLUGIN_VERSION;
113
  $result['iwpm_plugin_data']=$data;
114
+ $result['iwpm_plugin_install_date']=$tcmp->Options->getPluginInstallDate();
115
+ $result['iwpm_plugin_update_date']=$tcmp->Options->getPluginUpdateDate();
116
 
117
+ $result['iwpm_license_key']=$tcmp->Options->getLicenseKey();
118
+ $result['iwpm_license_status']=$tcmp->Options->isLicenseSuccess();
119
+ $result['iwpm_tracking_enable']=$tcmp->Options->isTrackingEnable();
120
+ $result['iwpm_logger_enable']=$tcmp->Options->isLoggerEnable();
121
+ $result['iwpm_feedback_email']=$tcmp->Options->getFeedbackEmail();
122
 
123
  //var_dump($result);
124
  return $result;
126
 
127
  //send tracking data info to our server
128
  public function sendTracking($override = FALSE) {
129
+ global $tcmp;
130
 
131
  $result=-1;
132
+ if(!$override && !$tcmp->Options->isTrackingEnable())
133
  return $result;
134
 
135
  // Send a maximum of once per week
136
+ $last_send=$tcmp->Options->getTrackingLastSend();
137
  if(!$override && $last_send>strtotime('-1 week'))
138
  return $result;
139
 
141
  //add_filter('https_ssl_verify', '__return_false');
142
  //add_filter('block_local_requests', '__return_false');
143
 
144
+ $data=$tcmp->Utils->remotePost('usage', $this->getData());
145
  if($data) {
146
  $result=intval($data['id']);
147
+ $tcmp->Options->setTrackingLastSend(time());
148
  }
149
  return $result;
150
  }
151
 
152
  public function enableTracking() {
153
+ global $tcmp;
154
 
155
+ $tcmp->Options->setTrackingEnable(TRUE);
156
+ $tcmp->Options->setTrackingNotice(FALSE);
157
  $this->sendTracking(TRUE);
158
  }
159
  public function disableTracking() {
160
+ global $tcmp;
161
 
162
+ $tcmp->Options->setTrackingEnable(FALSE);
163
+ $tcmp->Options->setTrackingNotice(FALSE);
164
  $this->sendTracking(TRUE);
165
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  }
includes/classes/utils/Utils.php ADDED
@@ -0,0 +1,2784 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) exit;
3
+
4
+ class TCMP_Utils {
5
+ const FORMAT_DATETIME='d/m/Y H:i';
6
+ const FORMAT_COMPACT_DATETIME='d/m H:i';
7
+ const FORMAT_DATE='d/m/Y';
8
+ const FORMAT_TIME='H:i';
9
+
10
+ const FORMAT_SQL_DATETIME='Y-m-d H:i:s';
11
+ const FORMAT_SQL_DATE='Y-m-d';
12
+ const FORMAT_SQL_TIME='H:i:s';
13
+
14
+ private $colorIndex;
15
+ private $defaultCurrencySymbol;
16
+
17
+ public function __construct() {
18
+ $this->colorIndex=0;
19
+ }
20
+
21
+ public function setDefaultCurrencySymbol($value) {
22
+ $this->defaultCurrencySymbol=$value;
23
+ }
24
+ public function getDefaultCurrencySymbol() {
25
+ return ($this->defaultCurrencySymbol=='' ? 'USD' : $this->defaultCurrencySymbol);
26
+ }
27
+ function format($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
28
+ if($v1 || $v2 || $v3 || $v4 || $v5) {
29
+ $message=sprintf($message, $v1, $v2, $v3, $v4, $v5);
30
+ }
31
+ return $message;
32
+ }
33
+ function startsWith($haystack, $needle) {
34
+ $length=strlen($needle);
35
+ return (substr($haystack, 0, $length) === $needle);
36
+ }
37
+
38
+ function endsWith($haystack, $needle) {
39
+ $length=strlen($needle);
40
+ $start=$length * -1; //negative
41
+ return (substr($haystack, $start) === $needle);
42
+ }
43
+ function substr($text, $start=0, $end=-1) {
44
+ if($end<0) {
45
+ $end=strlen($text);
46
+ }
47
+ $length=$end-$start;
48
+ return substr($text, $start, $length);
49
+ }
50
+
51
+ function shortcodeArgs($args, $defaults) {
52
+ $args=$this->sanitizeShortcodeKeys($args);
53
+ $defaults=$this->sanitizeShortcodeKeys($defaults);
54
+ $args=shortcode_atts($defaults, $args);
55
+ return $args;
56
+ }
57
+ function sanitizeShortcodeKeys($array) {
58
+ $result=array();
59
+ foreach($array as $k=>$v) {
60
+ if(is_string($k)) {
61
+ $k=strtolower($k);
62
+ }
63
+ $result[$k]=$v;
64
+ }
65
+ return $result;
66
+ }
67
+
68
+ //WOW! $end is passed as reference due to we can change it if we found \n character after
69
+ //substring to avoid having these characters after or before
70
+ function substrln($text, $start=0, &$end=-1) {
71
+ if($end<0) {
72
+ $end=strlen($text);
73
+ }
74
+
75
+ do {
76
+ $loop=FALSE;
77
+ $c=substr($text, $end, 1);
78
+ if($c=="\n" || $c=="\r" || $c==".") {
79
+ $end += 1;
80
+ $loop=TRUE;
81
+ }
82
+ } while($loop);
83
+
84
+ $length=$end-$start;
85
+ return substr($text, $start, $length);
86
+ }
87
+
88
+ function toCommaArray($array, $isNumeric=TRUE, $isTrim=TRUE) {
89
+ if(is_string($array)) {
90
+ if(trim($array)=='') {
91
+ $array=array();
92
+ } else {
93
+ $array=explode(',', $array);
94
+ }
95
+ } elseif(is_numeric($array)) {
96
+ $array=array($array);
97
+ }
98
+ if(!is_array($array)) {
99
+ $array=array();
100
+ }
101
+ for($i=0; $i<count($array); $i++) {
102
+ if($isTrim) {
103
+ $array[$i]=trim($array[$i]);
104
+ }
105
+ if($isNumeric) {
106
+ $array[$i]=floatval($array[$i]);
107
+ }
108
+ }
109
+ return $array;
110
+ }
111
+ function inAllArray($search, $where) {
112
+ return ($this->inArray(-1, $where) || $this->inArray($search, $where));
113
+ }
114
+ function inArray($search, $where) {
115
+ $result=FALSE;
116
+ $where=$this->toArray($where);
117
+ $search=$this->toArray($search);
118
+ if(count($where)==0 || count($search)==0) {
119
+ return FALSE;
120
+ }
121
+
122
+ foreach($where as $v) {
123
+ $v.='';
124
+ foreach($search as $c) {
125
+ $c.='';
126
+ if($v===$c) {
127
+ $result=TRUE;
128
+ break;
129
+ }
130
+ }
131
+ /*$v=intval($v);
132
+ if ($v<0) {
133
+ //if one element of the array have -1 value means i select "all" option
134
+ $result=TRUE;
135
+ break;
136
+ }*/
137
+
138
+ if($result) {
139
+ break;
140
+ }
141
+ }
142
+ return $result;
143
+ }
144
+
145
+ function is($name, $compare, $default='', $ignoreCase=TRUE) {
146
+ $what=$this->qs($name, $default);
147
+ $result=FALSE;
148
+ if(is_string($compare)) {
149
+ $compare=explode(',', $compare);
150
+ }
151
+ if($ignoreCase){
152
+ $what=strtolower($what);
153
+ }
154
+
155
+ foreach($compare as $v) {
156
+ if($ignoreCase){
157
+ $v=strtolower($v);
158
+ }
159
+ if($what==$v) {
160
+ $result=TRUE;
161
+ break;
162
+ }
163
+ }
164
+ return $result;
165
+ }
166
+
167
+ public function twitter($name) {
168
+ ?>
169
+ <a href="https://twitter.com/<?php echo $name?>" class="twitter-follow-button" data-show-count="false" data-dnt="true">Follow @<?php echo $name?></a>
170
+ <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
171
+ <?php
172
+ }
173
+
174
+ public function sort($isAssociative, $a1, $a2=NULL, $a3=NULL, $a4=NULL, $a5=NULL) {
175
+ $array=$this->merge($isAssociative, $a1, $a2, $a3, $a4, $a5);
176
+ ksort($array);
177
+ return $array;
178
+ }
179
+ public function merge($isAssociative, $a1, $a2=NULL, $a3=NULL, $a4=NULL, $a5=NULL) {
180
+ $result=array();
181
+ if($isAssociative) {
182
+ $array=array($a1, $a2, $a3, $a4, $a5);
183
+ foreach($array as $a) {
184
+ if(!is_array($a)) {
185
+ continue;
186
+ }
187
+
188
+ foreach($a as $k=>$v) {
189
+ if(!isset($result[$k])) {
190
+ $result[$k]=$v;
191
+ }
192
+ }
193
+ }
194
+ } else {
195
+ $result=array_merge($a1, $a2, $a3, $a4, $a5);
196
+ }
197
+ return $result;
198
+ }
199
+
200
+ function bget($instance, $name, $index=-1) {
201
+ $v=$this->get($instance, $name, FALSE, $index);
202
+ $v=$this->isTrue($v);
203
+ return $v;
204
+ }
205
+ function dget($instance, $name, $index=-1) {
206
+ $v=$this->get($instance, $name, FALSE, $index);
207
+ $v=$this->parseDateToTime($v);
208
+ return $v;
209
+ }
210
+ function aget($instance, $name, $index=-1) {
211
+ $v=$this->get($instance, $name, FALSE, $index);
212
+ $v=$this->toArray($v);
213
+ return $v;
214
+ }
215
+ function get($instance, $name, $default='', $index=-1) {
216
+ if($this->isEmpty($instance)) {
217
+ return $default;
218
+ }
219
+ $options=array();
220
+ //assolutamente da non fare altrimenti succede un disastro in quanto i metodi del inputComponent
221
+ //gli passano come name il valore...insomma un disastro!
222
+ //$name=$this->toArray($name);
223
+ //$name=implode('.', $name);
224
+
225
+ $result=$default;
226
+ if(is_array($instance) || is_object($instance)) {
227
+ if($this->propertyReflect($instance, $name, $options)) {
228
+ $result=$options['get'];
229
+ }
230
+ }
231
+ if($index>-1) {
232
+ $result=$this->toArray($result);
233
+ if(isset($result[$index])) {
234
+ $result=$result[$index];
235
+ } else {
236
+ $result=$default;
237
+ }
238
+ }
239
+ return $result;
240
+ }
241
+ function has($instance, $name) {
242
+ return $this->propertyReflect($instance, $name);
243
+ }
244
+ function set(&$instance, $name, $value) {
245
+ $options=array('set'=>$value);
246
+ $result=$this->propertyReflect($instance, $name, $options);
247
+ if(!$result) {
248
+ }
249
+ return $result;
250
+ }
251
+ function iget($array, $name, $default='') {
252
+ return floatval($this->get($array, $name, $default));
253
+ }
254
+
255
+ private function propertyReflect(&$instance, $name, &$options=array()) {
256
+ if(!is_object($instance) && !is_array($instance)) {
257
+ return FALSE;
258
+ }
259
+
260
+ if($options===FALSE || !is_array($options)) {
261
+ $options=array();
262
+ }
263
+ $options['has']=FALSE;
264
+ $options['get']=FALSE;
265
+
266
+ $current=$instance;
267
+ $names=explode('.', $name);
268
+ $value=FALSE;
269
+ $result=TRUE;
270
+ for($i=0; $i<count($names); $i++) {
271
+ $name=$names[$i];
272
+ if(!is_object($current) && !is_array($current)) {
273
+ return FALSE;
274
+ }
275
+ if(is_null($current)) {
276
+ return FALSE;
277
+ }
278
+
279
+ if(is_object($current)) {
280
+ if(get_class($current)=='stdClass') {
281
+ if(isset($current->$name)) {
282
+ $value=$current->$name;
283
+ } else {
284
+ $result=FALSE;
285
+ }
286
+ } else {
287
+ $r=new ReflectionClass($current);
288
+ try {
289
+ if($r->getProperty($name)!==FALSE) {
290
+ $value=$current->$name;
291
+ } else {
292
+ $result=FALSE;
293
+ }
294
+ } catch(Exception $ex) {
295
+ if(isset($current->$name)) {
296
+ $value=$current->$name;
297
+ } else {
298
+ $result=FALSE;
299
+ }
300
+ }
301
+ }
302
+ } elseif(is_array($current)) {
303
+ if(isset($current[$name])) {
304
+ $value=$current[$name];
305
+ } else {
306
+ $result=FALSE;
307
+ }
308
+ }
309
+
310
+ if(!$result) {
311
+ break;
312
+ } elseif($i<(count($names)-1)) {
313
+ $current=$value;
314
+ } else {
315
+ $options['get']=$value;
316
+ if(isset($options['set'])) {
317
+ if(is_object($current)) {
318
+ $current->$name=$options['set'];
319
+ } elseif(is_array($current)) {
320
+ $current[$name]=$options['set'];
321
+ }
322
+ }
323
+ }
324
+ }
325
+ return $result;
326
+ }
327
+ function isTrue($value) {
328
+ $result=FALSE;
329
+ if(is_bool($value)) {
330
+ $result=(bool)$value;
331
+ } elseif(is_numeric($value)) {
332
+ $result=floatval($value)>0;
333
+ } else {
334
+ $result=strtolower($value);
335
+ if($result=='ok' || $result=='yes' || $result=='true' || $result=='on') {
336
+ $result=TRUE;
337
+ } else {
338
+ $result=FALSE;
339
+ }
340
+ }
341
+ return $result;
342
+ }
343
+ function aqs($prefix, $removePrefix=TRUE) {
344
+ $result=array();
345
+ $array=$this->merge(TRUE, $_POST, $_GET);
346
+ foreach($array as $k=>$v) {
347
+ if($this->startsWith($k, $prefix)) {
348
+ if($removePrefix) {
349
+ $k=substr($k, strlen($prefix));
350
+ }
351
+ $result[$k]=$v;
352
+ }
353
+ }
354
+ return $result;
355
+ }
356
+ function iqs($name, $default=0, $min=0, $max=0) {
357
+ $result=floatval($this->qs($name, $default));
358
+ if($min!=$max) {
359
+ if($result<$min) {
360
+ $result=$min;
361
+ } elseif($result>$max) {
362
+ $result=$max;
363
+ }
364
+ }
365
+ return $result;
366
+ }
367
+ function dqs($name, $default=0) {
368
+ $result=($this->qs($name, $default));
369
+ $result=$this->parseDateToTime($result);
370
+ if($result==0) {
371
+ $result=$default;
372
+ }
373
+ return $result;
374
+ }
375
+ //per ottenere un campo dal $_GET oppure dal $_POST
376
+ function qs($name, $default='') {
377
+ $result=$default;
378
+ if(isset($_POST[$name])) {
379
+ $result=$_POST[$name];
380
+ } elseif (isset($_GET[$name])) {
381
+ $result=$_GET[$name];
382
+ }
383
+
384
+ if (is_string($result)) {
385
+ //The superglobals $_GET and $_REQUEST are already decoded.
386
+ //Using urldecode() on an element in $_GET or $_REQUEST
387
+ //could have unexpected and dangerous results.
388
+ //$result=urldecode($result);
389
+ $result=trim($result);
390
+ }
391
+ return $result;
392
+ }
393
+
394
+ var $_taxonomyType;
395
+ private function getTermLink($id) {
396
+ if(is_array($id)) {
397
+ foreach($id as $v) {
398
+ $id=$v;
399
+ break;
400
+ }
401
+ }
402
+ if(is_numeric($id)) {
403
+ $id=intval($id);
404
+ }
405
+ $result=get_term_link($id, $this->_taxonomyType);
406
+ if(is_wp_error($result)) {
407
+ $result=FALSE;
408
+ }
409
+ return $result;
410
+ }
411
+ function query($query, $options=NULL) {
412
+ global $tcmp, $wpdb;
413
+
414
+ $parent='';
415
+ $defaults=array(
416
+ 'post_type' => ''
417
+ , 'all' => FALSE
418
+ , 'select' => FALSE
419
+ , 'taxonomy'=>''
420
+ );
421
+ $options=wp_parse_args($options, $defaults);
422
+
423
+ if(!isset($options['type'])) {
424
+ if($options['post_type']!='') {
425
+ $options['type']=$options['post_type'];
426
+ } elseif($options['taxonomy']!='') {
427
+ $options['type']=$options['taxonomy'];
428
+ } else {
429
+ $options['type']='';
430
+ }
431
+ }
432
+
433
+ if($query==TCMP_QUERY_CONVERSION_PLUGINS) {
434
+ $array=$tcmp->Ecommerce->getPlugins(FALSE);
435
+ $result=array();
436
+ foreach($array as $k=>$v) {
437
+ $result[]=$v;
438
+ }
439
+ } else {
440
+ $key=array('Query', $query.'_'.$options['type']);
441
+ $result=$tcmp->Options->getCache($key);
442
+ if (!is_array($result) || count($result) == 0) {
443
+ $q=NULL;
444
+ $id='ID';
445
+ $name='post_title';
446
+ $function='';
447
+ switch ($query) {
448
+ case TCMP_QUERY_POSTS_OF_TYPE:
449
+ //$options=array('posts_per_page'=>-1, 'post_type'=>$args['post_type']);
450
+ //$q=get_posts($options);
451
+ $sql="SELECT ID, post_title FROM ".$wpdb->prefix."posts WHERE post_status='publish' AND post_type='".$options['type']."' ORDER BY post_title";
452
+ $q=$wpdb->get_results($sql);
453
+ $function='get_permalink';
454
+ break;
455
+ case TCMP_QUERY_CATEGORIES:
456
+
457
+ break;
458
+ case TCMP_QUERY_TAGS:
459
+
460
+ break;
461
+ case TCMP_QUERY_TAXONOMIES_OF_TYPE:
462
+
463
+ break;
464
+ }
465
+
466
+ $result=array();
467
+ if ($q) {
468
+ if(!is_wp_error($q)) {
469
+ foreach ($q as $v) {
470
+ $item=array('id' => $v->$id, 'name' => $v->$name);
471
+ if($parent!='') {
472
+ $item['parent']=$v->$parent;
473
+ }
474
+ $result[]=$item;
475
+ }
476
+ }
477
+ } elseif ($query==TCMP_QUERY_POST_TYPES) {
478
+ global $wp_post_types;
479
+ $result=array();
480
+ foreach($wp_post_types as $k=>$v) {
481
+ $isPublic=$tcmp->Utils->bget($v, 'public');
482
+ if($isPublic && $k!='attachment') {
483
+ $v=$tcmp->Utils->get($v, 'labels.singular_name');
484
+ if($k=='post' || $k=='page') {
485
+ $result[$k]=$v;
486
+ }
487
+ }
488
+ }
489
+ $result=$tcmp->Utils->toFormatListArrayFromListObjects($result, FALSE, '{text} ({id})');
490
+ } elseif($query==TCMP_QUERY_TAXONOMY_TYPES) {
491
+
492
+ }
493
+
494
+ if($this->functionExists($function)) {
495
+ for($i=0; $i<count($result); $i++) {
496
+ $v=$result[$i];
497
+ $v['url']=$this->functionCall($function, array($v['id']));
498
+ $result[$i]=$v;
499
+ }
500
+ }
501
+ $tcmp->Options->setCache($key, $result);
502
+ }
503
+ }
504
+
505
+ if ($options['all']) {
506
+ $first=array();
507
+ $first[]=array('id'=>-1, 'name'=>'['.$tcmp->Lang->L('All').']', 'url'=>'');
508
+ $result=array_merge($first, $result);
509
+ }
510
+ if ($options['select']) {
511
+ $first=array();
512
+ $first[]=array('id'=>0, 'name'=>'['.$tcmp->Lang->L('Select').']', 'url'=>'');
513
+ $result=array_merge($first, $result);
514
+ }
515
+ $result=$this->sortOptions($result);
516
+ $this->_taxonomyType='';
517
+ return $result;
518
+ }
519
+
520
+ //wp_parse_args with null correction
521
+ function parseArgs($options, $defaults) {
522
+ if (is_null($options)) {
523
+ $options=array();
524
+ } elseif(is_object($options)) {
525
+ $options=(array)$options;
526
+ } elseif(!is_array($options)) {
527
+ $options=array();
528
+ }
529
+ if (is_null($defaults)) {
530
+ $defaults=array();
531
+ } elseif(is_object($defaults)) {
532
+ $defaults=(array)$defaults;
533
+ } elseif(!is_array($defaults)) {
534
+ $defaults=array();
535
+ }
536
+
537
+ foreach($defaults as $k=>$v) {
538
+ if(is_null($v)) {
539
+ unset($defaults[$k]);
540
+ }
541
+ }
542
+
543
+ foreach($options as $k=>$v) {
544
+ if(isset($defaults[$k])) {
545
+ if (is_null($v)) {
546
+ //so can take the default value
547
+ unset($options[$k]);
548
+ } elseif (is_string($v) && ($v==='') && isset($defaults[$k]) && is_array($defaults[$k])) {
549
+ //a very strange case, i have a blank string for rappresenting an empty array
550
+ unset($options[$k]);
551
+ } else {
552
+ unset($defaults[$k]);
553
+ }
554
+ }
555
+ }
556
+ foreach($defaults as $k=>$v) {
557
+ $options[$k]=$v;
558
+ }
559
+ return $options;
560
+ }
561
+
562
+ function redirect($location) {
563
+ if($location=='') {
564
+ return;
565
+ }
566
+ //seems that if you have installed xdebug (or some version of it) doesnt work so js added
567
+ if(!headers_sent()) {
568
+ wp_redirect($location);
569
+ }
570
+ ?>
571
+ <script> window.location.replace('<?php echo $location?>'); </script>
572
+ <?php
573
+ die();
574
+ }
575
+
576
+ //return the element inside array with the specified key
577
+ function getArrayValue($key, $array, $value='') {
578
+ $result=FALSE;
579
+ if (isset($array[$key])) {
580
+ $result=$array[$key];
581
+ $result['name']=$key;
582
+ }
583
+ if($result!==FALSE && $value!='') {
584
+ if(isset($result[$value])) {
585
+ $result=$result[$value];
586
+ }
587
+ }
588
+ return $result;
589
+ }
590
+
591
+ var $_sortField;
592
+ var $_ignoreCase;
593
+ function aksort(&$array, $sortField='name', $ignoreCase=TRUE) {
594
+ $this->_sortField=$sortField;
595
+ $this->_ignoreCase=$ignoreCase;
596
+ usort($array, array($this, "aksortCompare"));
597
+ }
598
+ //not thread-safe!
599
+ private function aksortCompare($a, $b) {
600
+ if ($a===$b || $a==$b) {
601
+ return 0;
602
+ }
603
+
604
+ $result=0;
605
+ $a=$a[$this->_sortField];
606
+ $b=$b[$this->_sortField];
607
+ if(is_numeric($a) && is_numeric($b)) {
608
+ $result=($a < $b) ? -1 : 1;
609
+ } else {
610
+ $a.='';
611
+ $b.='';
612
+ if($this->_ignoreCase) {
613
+ $result=strcasecmp($a, $b);
614
+ } else {
615
+ $result=strcmp($a.'', $b);
616
+ }
617
+ }
618
+ return $result;
619
+ }
620
+
621
+ function printScriptCss() {
622
+ global $tcmp;
623
+ $uri=get_bloginfo('wpurl');
624
+ $tcmp->Tabs->enqueueScripts();
625
+ //wp_enqueue_style('buttons', $uri.'/wp-includes/css/buttons.min.css');
626
+ //wp_enqueue_style('editor', $uri.'/wp-includes/css/editor.min.css');
627
+ //wp_enqueue_style('jquery-ui-dialog', $uri.'/wp-includes/css/jquery-ui-dialog.min.css');
628
+ $styles='dashicons,admin-bar,buttons,media-views,wp-admin,wp-auth-check,wp-color-picker';
629
+ $styles=explode(',', $styles);
630
+ foreach($styles as $v) {
631
+ wp_enqueue_style($v);
632
+ }
633
+
634
+ remove_all_actions('wp_print_scripts');
635
+ print_head_scripts();
636
+ print_admin_styles();
637
+ }
638
+
639
+ public function formatCustomDate($time, $format) {
640
+ $time=$this->parseDateToTime($time);
641
+ if($time>0) {
642
+ $time=date($format, $time);
643
+ } else {
644
+ $time='';
645
+ }
646
+ return $time;
647
+ }
648
+
649
+ public function formatDatetime($time='now') {
650
+ return $this->formatCustomDate($time, TCMP_Utils::FORMAT_DATETIME);
651
+ }
652
+ public function formatCompactDatetime($time='now') {
653
+ return $this->formatCustomDate($time, TCMP_Utils::FORMAT_COMPACT_DATETIME);
654
+ }
655
+ public function formatDate($time='date') {
656
+ return $this->formatCustomDate($time, TCMP_Utils::FORMAT_DATE);
657
+ }
658
+ public function formatSmartDatetime($time='now') {
659
+ $time=$this->parseDateToTime($time);
660
+ $result='';
661
+ if($time>0) {
662
+ $h=intval(date('H', $time));
663
+ $i=intval(date('i', $time));
664
+ $s=intval(date('s', $time));
665
+ if($h==0 && $i==0 && $s==0) {
666
+ $result=$this->formatDate($time);
667
+ } else {
668
+ $result=$this->formatDatetime($time);
669
+ }
670
+ }
671
+ return $result;
672
+ }
673
+ public function formatTime($time='now') {
674
+ return $this->formatCustomTime($time, TCMP_Utils::FORMAT_TIME);
675
+ }
676
+ public function formatSqlDatetime($time='now') {
677
+ return $this->formatCustomDate($time, TCMP_Utils::FORMAT_SQL_DATETIME);
678
+ }
679
+ public function formatSqlDate($time='date') {
680
+ return $this->formatCustomDate($time, TCMP_Utils::FORMAT_SQL_DATE);
681
+ }
682
+ public function formatSqlTime($time='now') {
683
+ return $this->formatCustomTime($time, TCMP_Utils::FORMAT_SQL_TIME);
684
+ }
685
+
686
+ private function formatCustomTime($time, $format) {
687
+ $time=$this->parseDateToTime($time);
688
+ if($time>86400) {
689
+ $h=date('H', $time);
690
+ $i=date('i', $time);
691
+ $s=date('s', $time);
692
+ $time=$h*3600+$i*60+$s;
693
+ }
694
+
695
+ $s=$time%60;
696
+ $time=($time-$s)/60;
697
+ $i=$time%60;
698
+ $h=($time-$i)/60;
699
+ $s=str_pad($s, 2, "0", STR_PAD_LEFT);
700
+ $i=str_pad($i, 2, "0", STR_PAD_LEFT);
701
+ $h=str_pad($h, 2, "0", STR_PAD_LEFT);
702
+ $format=str_replace('H', $h, $format);
703
+ $format=str_replace('i', $i, $format);
704
+ $format=str_replace('s', $s, $format);
705
+ return $format;
706
+ }
707
+
708
+ public function parseNumber($what, $default=0) {
709
+ $result=$default;
710
+ if(is_array($what)) {
711
+ if(count($what)>0) {
712
+ $result=doubleval($what[0]);
713
+ }
714
+ }
715
+ elseif(is_numeric($what)) {
716
+ $result=doubleval($what);
717
+ } elseif(is_string($what) || is_bool($what)) {
718
+ $result=($this->isTrue($what) ? 1 : 0);
719
+ }
720
+ return $result;
721
+ }
722
+ public function parseDateToArray($date) {
723
+ global $tcmp;
724
+
725
+ $pm=FALSE;
726
+ $date=strtoupper(trim($date));
727
+ if($tcmp->Utils->endsWith($date, 'AM')) {
728
+ $date=substr($date, 0, strlen($date)-2);
729
+ $date=trim($date);
730
+ } elseif($tcmp->Utils->endsWith($date, 'PM')) {
731
+ $date=substr($date, 0, strlen($date)-2);
732
+ $date=trim($date);
733
+ $pm=TRUE;
734
+ }
735
+
736
+ $date=explode(' ', $date);
737
+ if(count($date)==1) {
738
+ $result=array();
739
+ $date=$date[0];
740
+ $date=str_replace("/", "-", $date);
741
+ if(strpos($date, '-')!==FALSE) {
742
+ $date=explode('-', $date);
743
+ if(count($date)>=3) {
744
+ $d=intval($date[0]);
745
+ $m=intval($date[1]);
746
+ $y=intval($date[2]);
747
+ if($d>1900) {
748
+ $t=$d;
749
+ $d=$y;
750
+ $y=$t;
751
+ }
752
+ if($y>0 && $m>0 && $d>0) {
753
+ $result['y']=$y;
754
+ $result['m']=$m;
755
+ $result['d']=$d;
756
+ }
757
+ }
758
+ } elseif(strpos($date, ':')!==FALSE) {
759
+ $date=explode(':', $date);
760
+ if(count($date)==2) {
761
+ $date[]=0;
762
+ }
763
+ if(count($date)>=3) {
764
+ $h=intval($date[0]);
765
+ $i=intval($date[1]);
766
+ $s=intval($date[2]);
767
+ if($h>=0 && $i>=0 && $s>=0) {
768
+ $result['h']=$h;
769
+ $result['i']=$i;
770
+ $result['s']=$s;
771
+ }
772
+ }
773
+ }
774
+ } else {
775
+ $a1=$this->parseDateToArray($date[0]);
776
+ $a2=$this->parseDateToArray($date[1]);
777
+ $result=$tcmp->Utils->parseArgs($a1, $a2);
778
+ }
779
+
780
+ if($pm && isset($result['h'])) {
781
+ $result['h']=intval($result['h'])+12;
782
+ }
783
+ return $result;
784
+ }
785
+ public function parseDateToTime($date) {
786
+ global $tcmp;
787
+ if(is_numeric($date) || trim($date)=='') {
788
+ $date=intval($date);
789
+ return $date;
790
+ }
791
+
792
+ $date=strtolower($date);
793
+ if($date=='now') {
794
+ $date=time();
795
+ return $date;
796
+ } elseif($date=='date') {
797
+ $date=strtotime(date('Y-m-d', time()));
798
+ return $date;
799
+ } elseif($date=='time') {
800
+ $date=date('H:i:s', time());
801
+ }
802
+ $result=$this->parseDateToArray($date);
803
+ $defaults=array('y'=>0, 'm'=>0, 'd'=>0, 'h'=>0, 'i'=>0, 's'=>0);
804
+ $a=$tcmp->Utils->parseArgs($result, $defaults);
805
+ if($a['y']==0 && $a['m']==0 && $a['d']==0) {
806
+ $result=$a['h']*3600+$a['i']*60+$a['s'];
807
+ } else {
808
+ $result=mktime($a['h'], $a['i'], $a['s'], $a['m'], $a['d'], $a['y']);
809
+ }
810
+ if($result<0) {
811
+ $result=0;
812
+ }
813
+ return $result;
814
+ }
815
+ public function getIntDate($time, $separator='') {
816
+ $time=$this->parseDateToTime($time);
817
+ if($time>0) {
818
+ if($separator=='') {
819
+ $time=date('Ymd', $time);
820
+ $time=intval($time);
821
+ } else {
822
+ $time=date('Y', $time).$separator.date('m', $time).$separator.date('d', $time);
823
+ }
824
+ }
825
+
826
+ return $time;
827
+ }
828
+ public function getIntMinute($h, $m, $separator='') {
829
+ $h=intval($h);
830
+ $m=intval($m);
831
+ if($m<10) {
832
+ $m='0'.$m;
833
+ }
834
+ $result=$h.$separator.$m;
835
+ if($separator=='') {
836
+ $result=intval($result);
837
+ }
838
+ return $result;
839
+ }
840
+
841
+ //args can be a string or an associative array if you want
842
+ public function getTextArgs($args, $defaults=array(), $excludes=array()) {
843
+ $result=$args;
844
+ $excludes=$this->toArray($excludes);
845
+ if(is_array($result) && count($result)>0) {
846
+ $result='';
847
+ foreach($args as $k=>$v) {
848
+ if(is_array($v) || is_object($v)) {
849
+ continue;
850
+ }
851
+
852
+ if(count($excludes)==0 || !in_array($k, $excludes)) {
853
+ $v=trim($v);
854
+ $result.=' '.$k.'="'.$v.'"';
855
+ }
856
+ }
857
+ } elseif(!$args) {
858
+ $result='';
859
+ }
860
+ if(is_array($defaults) && count($defaults)>0) {
861
+ foreach($defaults as $k=>$v) {
862
+ if(count($excludes)==0 || !in_array($k, $excludes)) {
863
+ if(!isset($args[$k])) {
864
+ $v=trim($v);
865
+ $result.=' '.$k.'="'.$v.'"';
866
+ }
867
+ }
868
+ }
869
+ }
870
+ return $result;
871
+ }
872
+ public function queryString($uri, $options=array()) {
873
+ if(is_string($options)) {
874
+ $options=explode('&', $options);
875
+ $array=array();
876
+ foreach($options as $v) {
877
+ $v=explode('=', $v);
878
+ if(count($v)>1) {
879
+ $array[trim($v[0])]=trim($v[1]);
880
+ }
881
+ }
882
+ $options=$array;
883
+ }
884
+ if(!isset($options['root']) || $this->isTrue($options['root'])) {
885
+ $uri=TCMP_BLOG_URL.$uri;
886
+ }
887
+ unset($options['root']);
888
+ $uri=$this->addQueryString($options, $uri);
889
+ return $uri;
890
+ }
891
+ public function iuarray($ids, $positive=FALSE) {
892
+ $array=$this->iarray($ids, $positive);
893
+ $array=array_unique($array);
894
+ sort($array);
895
+ return $array;
896
+ }
897
+ public function iarray($ids, $positive=FALSE) {
898
+ if(is_string($ids)) {
899
+ $ids=explode(',', $ids);
900
+ } elseif(is_numeric($ids)) {
901
+ $ids=array($ids);
902
+ } elseif(!is_array($ids)) {
903
+ $ids=array();
904
+ }
905
+
906
+ $array=array();
907
+ foreach($ids as $v) {
908
+ $v=trim($v);
909
+ if($v!='') {
910
+ $v=intval($v);
911
+ if(!$positive || $v>0) {
912
+ $array[]=$v;
913
+ }
914
+ }
915
+ }
916
+ return $array;
917
+ }
918
+ public function dbarray($ids) {
919
+ if(is_string($ids)) {
920
+ $ids=explode(',', $ids);
921
+ } elseif(is_numeric($ids)) {
922
+ $ids=array($ids);
923
+ } elseif(!is_array($ids)) {
924
+ $ids=array();
925
+ }
926
+
927
+ $array=array();
928
+ foreach($ids as $v) {
929
+ $v=trim($v);
930
+ if($v!='') {
931
+ if(is_numeric($v)) {
932
+ $v=intval($v);
933
+ }
934
+ $array[]=$v;
935
+ }
936
+ }
937
+ return $array;
938
+ }
939
+
940
+ function isAssociativeArray($array) {
941
+ if(!is_array($array)) {
942
+ return FALSE;
943
+ }
944
+
945
+ $isArray=TRUE;
946
+ $i=0;
947
+ foreach($array as $k=>$v) {
948
+ if($k!==$i) {
949
+ $isArray=FALSE;
950
+ break;
951
+ }
952
+ ++$i;
953
+ }
954
+ return !$isArray;
955
+ }
956
+ function trim($value) {
957
+ if(is_null($value)) {
958
+
959
+ } elseif(is_string($value)) {
960
+ $value=trim($value);
961
+ } elseif(is_numeric($value)) {
962
+
963
+ } elseif($this->isAssociativeArray($value)) {
964
+ foreach($value as $k=>$v) {
965
+ $value[$k]=$this->trim($v);
966
+ }
967
+ } elseif(is_object($value)) {
968
+ foreach($value as $k=>$v) {
969
+ $value->$k=$this->trim($v);
970
+ }
971
+ } elseif(is_array($value)) {
972
+ for($i=0; $i<count($value); $i++) {
973
+ $v=$value[$i];
974
+ $this->trim($v);
975
+ $value[$i]=$v;
976
+ }
977
+ }
978
+ return $value;
979
+ }
980
+ function implode($open, $close, $join, $array) {
981
+ $result='';
982
+ foreach($array as $v) {
983
+ if($result!='') {
984
+ $result.=$join;
985
+ }
986
+ $result.=$open.$v.$close;
987
+ }
988
+ return $result;
989
+ }
990
+ function toArray($text, $index=-1, $default='') {
991
+ if(is_array($text)) {
992
+ if(is_string($index)) {
993
+ $array=array();
994
+ foreach($text as $v) {
995
+ $v=$this->get($v, $index, FALSE);
996
+ if($v!==FALSE) {
997
+ $array[]=$v;
998
+ }
999
+ }
1000
+ } else {
1001
+ $array=$text;
1002
+ }
1003
+ return $array;
1004
+ } elseif(is_numeric($text)) {
1005
+ return array($text);
1006
+ } elseif(is_bool($text) || $text==='') {
1007
+ return array();
1008
+ }
1009
+
1010
+ if(($this->startsWith($text, '[') && $this->endsWith($text, ']'))
1011
+ || ($this->startsWith($text, '{') && $this->endsWith($text, '}'))) {
1012
+ $text=substr($text, 1, strlen($text)-2);
1013
+ }
1014
+ $text=str_replace('|', ',', $text);
1015
+ $text=explode(',', $text);
1016
+
1017
+ //exclude empty string
1018
+ $array=array();
1019
+ foreach($text as $t) {
1020
+ if($t!=='') {
1021
+ $array[]=$t;
1022
+ }
1023
+ }
1024
+ $text=$array;
1025
+ if($index>-1) {
1026
+ $result=$default;
1027
+ if(isset($text[$index])) {
1028
+ $result=$text[$index];
1029
+ }
1030
+ $text=$result;
1031
+ }
1032
+ return $text;
1033
+ }
1034
+ function dirToFlatArray($dir, &$output) {
1035
+ if(!isset($output['dirs'])) {
1036
+ $output['dirs']=array();
1037
+ }
1038
+ if(!isset($output['files'])) {
1039
+ $output['files']=array();
1040
+ }
1041
+
1042
+ $cdir=scandir($dir);
1043
+ foreach ($cdir as $k=>$v) {
1044
+ if (!in_array($v,array(".",".."))) {
1045
+ if (is_dir($dir.DIRECTORY_SEPARATOR.$v)) {
1046
+ $i=$dir.DIRECTORY_SEPARATOR.$v;
1047
+ array_push($output['dirs'], $i);
1048
+ $this->dirToFlatArray($i, $output);
1049
+ } else {
1050
+ $i=$this->getFileInfo($dir.DIRECTORY_SEPARATOR.$v);
1051
+ array_push($output['files'], $i);
1052
+ }
1053
+ }
1054
+ }
1055
+ }
1056
+ function dirToArray($dir) {
1057
+ $result=array();
1058
+ if(!is_string($dir)) {
1059
+ return $result;
1060
+ }
1061
+
1062
+ $cdir=scandir($dir);
1063
+ foreach ($cdir as $k=>$v) {
1064
+ if (!in_array($v, array(".",".."))) {
1065
+ if (is_dir($dir.DIRECTORY_SEPARATOR.$v)) {
1066
+ $result[$v]=$this->dirToArray($dir.DIRECTORY_SEPARATOR.$v);
1067
+ } else {
1068
+ $result[]=$this->getFileInfo($dir.DIRECTORY_SEPARATOR.$v);
1069
+ }
1070
+ }
1071
+ }
1072
+ return $result;
1073
+ }
1074
+ function getFileInfo($source) {
1075
+ $source=$this->toDirectory($source);
1076
+ if(!file_exists($source)) {
1077
+ return FALSE;
1078
+ }
1079
+
1080
+ $array=explode(DIRECTORY_SEPARATOR, $source);
1081
+ $size=filesize($source);
1082
+ $source=array_pop($array);
1083
+ $directory=implode(DIRECTORY_SEPARATOR, $array).DIRECTORY_SEPARATOR;
1084
+
1085
+ $pos=strrpos($source, ".");
1086
+ $ext='';
1087
+ if($pos!==FALSE) {
1088
+ $name=substr($source, 0, $pos);
1089
+ $ext=strtolower(substr($source, $pos));
1090
+ }
1091
+ $array=array(
1092
+ 'directory'=>$directory
1093
+ , 'name'=>$name
1094
+ , 'file'=>$source
1095
+ , 'size'=>$size
1096
+ , 'textSize'=>$this->getFileTextSize($size)
1097
+ , 'ext'=>$ext
1098
+ , 'textExt'=>$this->getFileTextExt($source)
1099
+ );
1100
+ return $array;
1101
+ }
1102
+ function getFileTextSize($size) {
1103
+ $units=array('B', 'KB', 'MB', 'GB');
1104
+ for ($i=0; $i<count($units); $i++) {
1105
+ if($size<1024) {
1106
+ break;
1107
+ } else {
1108
+ $size/=1024;
1109
+ }
1110
+ }
1111
+ return intval($size).' '.$units[$i];
1112
+ }
1113
+ function getFileTextExt($source) {
1114
+ $ext=strrpos($source, ".");
1115
+ if($ext!==FALSE) {
1116
+ $ext=strtolower(substr($source, $ext+1));
1117
+ } else {
1118
+ $ext=$source;
1119
+ }
1120
+ $ext=strtolower($ext);
1121
+ $text='text';
1122
+ switch ($ext) {
1123
+ case 'doc':
1124
+ case 'docx':
1125
+ case 'odt':
1126
+ $text='word';
1127
+ break;
1128
+ case 'xls':
1129
+ case 'xlsx':
1130
+ case 'ods':
1131
+ $text='excel';
1132
+ break;
1133
+ case 'ppt':
1134
+ case 'pptx':
1135
+ case 'odp':
1136
+ $text='powerpoint';
1137
+ break;
1138
+ case 'zip':
1139
+ case 'tar':
1140
+ case 'gzip':
1141
+ case 'rar':
1142
+ case '7z':
1143
+ $text='archive';
1144
+ break;
1145
+ case 'mp3':
1146
+ case 'wav':
1147
+ $text='audio';
1148
+ break;
1149
+ case 'mpeg':
1150
+ case 'mpg':
1151
+ case 'avi':
1152
+ case 'mp4':
1153
+ $text='video';
1154
+ break;
1155
+ case 'gif':
1156
+ case 'jpg':
1157
+ case 'jpeg':
1158
+ case 'png':
1159
+ case 'bmp':
1160
+ $text='image';
1161
+ break;
1162
+ case 'pdf':
1163
+ $text='pdf';
1164
+ break;
1165
+ }
1166
+ return $text;
1167
+ }
1168
+ function match($value, $array, $default='', $ignoreCase=TRUE) {
1169
+ $result=$default;
1170
+ if($ignoreCase) {
1171
+ $value=strtolower($value);
1172
+ }
1173
+ foreach($array as $k=>$v) {
1174
+ $v=$this->toArray($v);
1175
+ foreach($v as $c) {
1176
+ if($ignoreCase) {
1177
+ $c=strtolower($c);
1178
+ }
1179
+ if($value==$c || strpos($value, $c)!==FALSE) {
1180
+ $result=$k;
1181
+ break;
1182
+ }
1183
+ }
1184
+
1185
+ if($result!==$default) {
1186
+ break;
1187
+ }
1188
+ }
1189
+ return $result;
1190
+ }
1191
+
1192
+ function pickColor() {
1193
+ $names=explode('|', 'primary|success|warning|danger|info|alert|system|dark');
1194
+ $colors=explode('|', '3498db|70ca63|f6bb42|df5640|3bafda|967adc|37bc9b|666');
1195
+
1196
+ $i=($this->colorIndex%count($colors));
1197
+ $names=$names[$i];
1198
+ $colors=$colors[$i];
1199
+ ++$this->colorIndex;
1200
+ return array($names, '#'.$colors);
1201
+ }
1202
+ function upperUnderscoreCase($text) {
1203
+ $text=$this->arrayCase($text);
1204
+ $text=implode('_', $text);
1205
+ $text=strtoupper($text);
1206
+ return $text;
1207
+ }
1208
+ function lowerUnderscoreCase($text) {
1209
+ $text=$this->upperUnderscoreCase($text);
1210
+ $text=strtolower($text);
1211
+ return $text;
1212
+ }
1213
+ function toDirectory($file, $mkdirs=FALSE) {
1214
+ $file=str_replace("\\", DIRECTORY_SEPARATOR, $file);
1215
+ $file=str_replace("/", DIRECTORY_SEPARATOR, $file);
1216
+ $file=str_replace(DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, $file);
1217
+
1218
+ if(is_dir($file) && !file_exists($file) && $mkdirs) {
1219
+ mkdir($file, 0777, TRUE);
1220
+ }
1221
+ return $file;
1222
+ }
1223
+ function getUploadName($name) {
1224
+ if($name=='') {
1225
+ return '';
1226
+ }
1227
+
1228
+ $name=$this->toDirectory($name);
1229
+ $name=explode(DIRECTORY_SEPARATOR, $name);
1230
+ $name=$name[count($name)-1];
1231
+ $ext='';
1232
+ $pos=strpos($name, '.');
1233
+ if($pos!==FALSE) {
1234
+ $ext=substr($name, $pos);
1235
+ $name=substr($name, 0, $pos);
1236
+ }
1237
+
1238
+ $buffer='';
1239
+ $name=str_split(strtolower($name));
1240
+ for($i=0; $i<count($name); $i++) {
1241
+ if($name[$i]>='a' && $name[$i]<='z') {
1242
+ $buffer.=$name[$i];
1243
+ } else {
1244
+ $buffer.=' ';
1245
+ }
1246
+ }
1247
+ while(strpos($buffer, ' ')!==FALSE) {
1248
+ $buffer=str_replace(' ', ' ', $buffer);
1249
+ }
1250
+ $buffer=trim($buffer);
1251
+ $buffer=str_replace(' ', '-', $buffer);
1252
+ $buffer.='-'.date('Ymd-His', time()).$ext;
1253
+ return $buffer;
1254
+ }
1255
+ function toListArrayFromClass($array, $id=FALSE, $value=FALSE) {
1256
+ global $tcmp;
1257
+ $result=array();
1258
+ if($array!==FALSE && count($array)>0) {
1259
+ foreach($array as $k=>$v) {
1260
+ if($id!==FALSE) {
1261
+ $k=$tcmp->Utils->get($v, $id);
1262
+ }
1263
+ if($value!==FALSE) {
1264
+ $v=$tcmp->Utils->get($v, $value);
1265
+ }
1266
+
1267
+ if($k!='' && $v!='') {
1268
+ $result[]=array(
1269
+ 'id'=>$k
1270
+ , 'text'=>$v
1271
+ , 'name'=>$v
1272
+ );
1273
+ }
1274
+ }
1275
+ }
1276
+ return $result;
1277
+ }
1278
+ function toFormatListArrayFromListObjects($array, $idField, $textFormat) {
1279
+ global $tcmp;
1280
+ $result=array();
1281
+ if($array!==FALSE && count($array)>0) {
1282
+ foreach($array as $i=>$e) {
1283
+ $text=$textFormat;
1284
+ $idExists=FALSE;
1285
+ if(is_array($e) || is_object($e)) {
1286
+ foreach($e as $k=>$v) {
1287
+ if($k=='id') {
1288
+ $idExists=TRUE;
1289
+ }
1290
+ if(is_array($v)) {
1291
+ $v=implode(', ', $v);
1292
+ }
1293
+ $text=str_replace("{".$k."}", $v, $text);
1294
+ }
1295
+ } else {
1296
+ $text=str_replace("{text}", $e, $text);
1297
+ }
1298
+
1299
+ $id=$i;
1300
+ if($idField!==FALSE && $idField!=='') {
1301
+ $id=$tcmp->Utils->get($e, $idField, '');
1302
+ }
1303
+
1304
+ if(!$idExists) {
1305
+ $text=str_replace("{id}", $id, $text);
1306
+ }
1307
+ if($id!='') {
1308
+ $result[]=array(
1309
+ 'id'=>$id
1310
+ , 'text'=>$text
1311
+ , 'name'=>$text
1312
+ );
1313
+ }
1314
+ }
1315
+ }
1316
+ return $result;
1317
+ }
1318
+ function toListArrayFromListObjects($array
1319
+ , $idFrom=FALSE, $textFrom='name', $idTo='id', $textTo='text') {
1320
+
1321
+ $result=array();
1322
+ foreach($array as $v) {
1323
+ $sId=$v;
1324
+ $sText=$v;
1325
+ if($idFrom!==FALSE) {
1326
+ $sId=$this->get($v, $idFrom, FALSE);
1327
+ $sText=$this->get($v, $textFrom, FALSE);
1328
+ }
1329
+ if($sId!==FALSE && $sText!='') {
1330
+ if($sId!='') {
1331
+ $result[]=array(
1332
+ $idTo=>$sId
1333
+ , $textTo=>$sText
1334
+ );
1335
+ }
1336
+ }
1337
+ }
1338
+ return $result;
1339
+ }
1340
+ function toColorListArrayFromListObjects($array, $colors, $id='id', $text='name') {
1341
+ global $tcmp;
1342
+ $result=array();
1343
+ foreach($array as $instance) {
1344
+ $sId=$this->get($instance, $id, FALSE);
1345
+ $sText=$this->get($instance, $text, FALSE);
1346
+ foreach($colors as $color=>$when) {
1347
+ $success=FALSE;
1348
+ foreach($when['conditions'] as $conditionKey=>$conditionValue) {
1349
+ $conditionValue=$tcmp->Utils->toArray($conditionValue);
1350
+ $c=$this->get($instance, $conditionKey, FALSE);
1351
+ if($c!==FALSE) {
1352
+ $c.='';
1353
+ foreach($conditionValue as $v) {
1354
+ $v.='';
1355
+ if($c===$v) {
1356
+ $success=TRUE;
1357
+ break;
1358
+ }
1359
+ }
1360
+ }
1361
+ if($success) {
1362
+ break;
1363
+ }
1364
+ }
1365
+
1366
+ if($success) {
1367
+ $style='color:'.$color.'; ';
1368
+ if(isset($when['bold']) && $when['bold']) {
1369
+ $style.='font-weight:bold; ';
1370
+ }
1371
+ $sText='<span style="'.$style.'">'.$sText.'</span>';
1372
+ }
1373
+ }
1374
+ if($sId!='' && $sText!==FALSE) {
1375
+ $result[]=array(
1376
+ 'id'=>$sId
1377
+ , 'text'=>$sText
1378
+ , 'name'=>$sText
1379
+ );
1380
+ }
1381
+ }
1382
+ return $result;
1383
+ }
1384
+ function md5() {
1385
+ $array=func_get_args();
1386
+ $buffer='';
1387
+ foreach($array as $v) {
1388
+ $buffer.=':)'.$v;
1389
+ }
1390
+ $buffer=md5($buffer);
1391
+ return $buffer;
1392
+ }
1393
+ function arrayCase($text) {
1394
+ $buffer='';
1395
+ $array=array();
1396
+ $text=str_split($text);
1397
+ $prevUpper=FALSE;
1398
+ $nextUpper=FALSE;
1399
+ foreach($text as $c) {
1400
+ if($c>='a' && $c<='z') {
1401
+ if($nextUpper) {
1402
+ if($buffer!='') {
1403
+ $array[]=$buffer;
1404
+ $buffer='';
1405
+ }
1406
+ $c=strtoupper($c);
1407
+ }
1408
+ $buffer.=$c;
1409
+ $nextUpper=FALSE;
1410
+ $prevUpper=FALSE;
1411
+ } elseif($c>='0' && $c<='9') {
1412
+ $buffer.=$c;
1413
+ $nextUpper=TRUE;
1414
+ } elseif($c>='A' && $c<='Z') {
1415
+ if(!$prevUpper) {
1416
+ if($buffer!='') {
1417
+ $array[]=$buffer;
1418
+ $buffer='';
1419
+ }
1420
+ }
1421
+ $buffer.=$c;
1422
+ $nextUpper=FALSE;
1423
+ $prevUpper=TRUE;
1424
+ } else {
1425
+ if($buffer!='') {
1426
+ $array[]=$buffer;
1427
+ $buffer='';
1428
+ }
1429
+ $nextUpper=TRUE;
1430
+ $prevUpper=FALSE;
1431
+ }
1432
+ }
1433
+ if($buffer!='') {
1434
+ $array[]=$buffer;
1435
+ }
1436
+ return $array;
1437
+ }
1438
+ function lowerCamelCase($text) {
1439
+ $buffer='';
1440
+ if(strpos($text, '_')!==FALSE || strpos($text, '-')!==FALSE) {
1441
+ $text=strtolower($text);
1442
+ }
1443
+
1444
+ $text=str_split($text);
1445
+ $allUpper=TRUE;
1446
+ $nextUpper=FALSE;
1447
+ foreach($text as $c) {
1448
+ if($c>='a' && $c<='z') {
1449
+ $allUpper=FALSE;
1450
+ if($nextUpper) {
1451
+ $c=strtoupper($c);
1452
+ }
1453
+ $buffer.=$c;
1454
+ $nextUpper=FALSE;
1455
+ } elseif($c>='0' && $c<='9') {
1456
+ $buffer.=$c;
1457
+ $nextUpper=TRUE;
1458
+ } elseif($c>='A' && $c<='Z') {
1459
+ $buffer.=$c;
1460
+ $nextUpper=FALSE;
1461
+ } else {
1462
+ $nextUpper=TRUE;
1463
+ }
1464
+ }
1465
+ if($allUpper) {
1466
+ $buffer=strtolower($buffer);
1467
+ } else {
1468
+ $buffer=lcfirst($buffer);
1469
+ }
1470
+ return $buffer;
1471
+ }
1472
+ function upperCamelCase($text) {
1473
+ $text=$this->lowerCamelCase($text);
1474
+ $text=ucfirst($text);
1475
+ return $text;
1476
+ }
1477
+
1478
+ function castStdClass($a) {
1479
+ $a=(array)$a;
1480
+ $r=new stdClass();
1481
+ foreach($a as $k=>$v) {
1482
+ $r->$k=$v;
1483
+ }
1484
+ return $r;
1485
+ }
1486
+ function castArray($a) {
1487
+ $r=$a;
1488
+ if(is_object($a)) {
1489
+ $r=(array)$a;
1490
+ }
1491
+
1492
+ if(!is_array($r)) {
1493
+ $r=array();
1494
+ }
1495
+ return $r;
1496
+ }
1497
+ public function copyArray($array) {
1498
+ $temp=array();
1499
+ foreach($array as $k=>$v) {
1500
+ $temp[$k]=$v;
1501
+ }
1502
+ return $temp;
1503
+ }
1504
+ public function isObject($v) {
1505
+ return ($v!==FALSE && !is_null($v) && is_object($v));
1506
+ }
1507
+ public function isArray($v) {
1508
+ return ($v!==FALSE && !is_null($v) && is_array($v));
1509
+ }
1510
+ public function getConstants($class, $prefix, $reverse=FALSE) {
1511
+ global $tcmp;
1512
+ if(is_object($class)) {
1513
+ $class=get_class($class);
1514
+ }
1515
+ $class=str_replace('Search', '', $class);
1516
+ $class=str_replace('Constants', '', $class);
1517
+ $class.='Constants';
1518
+ if(!class_exists($class)) {
1519
+ $class=TCMP_PLUGIN_PREFIX.$class;
1520
+ }
1521
+
1522
+ $result=array();
1523
+ if(class_exists($class)) {
1524
+ $reflection=new ReflectionClass($class);
1525
+ $array=$reflection->getConstants();
1526
+ foreach($array as $k=>$v) {
1527
+ $pos=0;
1528
+ if($prefix!='') {
1529
+ $pos=stripos($k, $prefix);
1530
+ }
1531
+ if($pos===0) {
1532
+ if($reverse) {
1533
+ $result[$v]=$k;
1534
+ } else {
1535
+ $result[$k]=$v;
1536
+ }
1537
+ }
1538
+ }
1539
+ }
1540
+ return $result;
1541
+ }
1542
+ public function getConstantValue($class, $prefix, $name, $default=FALSE) {
1543
+ /* @var $ec TCMP_Singleton */
1544
+ global $ec;
1545
+ $result=$default;
1546
+ if(is_object($class)) {
1547
+ $class=get_class($class);
1548
+ }
1549
+ $class=str_replace('Search', '', $class);
1550
+ $class=str_replace('Constants', '', $class);
1551
+ $class.='Constants';
1552
+ if(!class_exists($class)) {
1553
+ $class=TCMP_PLUGIN_PREFIX.$class;
1554
+ }
1555
+
1556
+ if(class_exists($class)) {
1557
+ $name=$prefix.'_'.$name;
1558
+ $name=$ec->Utils->upperUnderscoreCase($name);
1559
+ $reflection=new ReflectionClass($class);
1560
+ $result=$reflection->getConstant($name);
1561
+ }
1562
+ return $result;
1563
+ }
1564
+ public function getConstantName($class, $prefix, $value, $default=FALSE) {
1565
+ /* @var $ec TCMP_Singleton */
1566
+ $constants=$this->getConstants($class, $prefix, TRUE);
1567
+ $result=$default;
1568
+ if(isset($constants[$value])) {
1569
+ $result=$constants[$value];
1570
+ }
1571
+ return $result;
1572
+ }
1573
+ public function daysDiff($dt1, $dt2) {
1574
+ $dt1=$this->parseDateToTime($dt1);
1575
+ $dt2=$this->parseDateToTime($dt2);
1576
+ $result=($dt2-$dt1)/86400;
1577
+ $result=intval($result);
1578
+ return $result;
1579
+ }
1580
+ public function getFirstLastDayOfWeek($dt) {
1581
+ $dt=$this->parseDateToTime($dt);
1582
+ // Get the day of the week: Sunday=0 to Saturday=6
1583
+ $dotw=date('w', $dt);
1584
+ if($dotw>1) {
1585
+ $dt1=$dt-(($dotw-1)*24*60*60);
1586
+ $dt2=$dt+((7-$dotw)*24*60*60);
1587
+ }
1588
+ else if($dotw==1) {
1589
+ $dt1=$dt;
1590
+ $dt2=$dt+((7-$dotw)*24*60*60);
1591
+ } else if($dotw==0) {
1592
+ $dt1=$dt -(6*24*60*60);;
1593
+ $dt2=$dt;
1594
+ }
1595
+
1596
+ $result=array($dt1, $dt2);
1597
+ return $result;
1598
+ }
1599
+ public function toMap($array, $key=FALSE, $value=FALSE, $classes=FALSE) {
1600
+ $classes=$this->toArray($classes);
1601
+ $result=array();
1602
+ if(is_string($array)) {
1603
+ $array=$this->toArray($array);
1604
+ $key=FALSE;
1605
+ $value=FALSE;
1606
+ }
1607
+ if(!is_array($array)) {
1608
+ $array=array();
1609
+ }
1610
+
1611
+ $assoc=$this->isAssociativeArray($array);
1612
+ foreach($array as $k=>$v) {
1613
+ if(!$assoc) {
1614
+ $k=$v;
1615
+ }
1616
+
1617
+ if($classes!==FALSE && count($classes)>0 && is_object($v)) {
1618
+ $class=get_class($v);
1619
+ if(!in_array($class, $classes)) {
1620
+ continue;
1621
+ }
1622
+ }
1623
+
1624
+ if($key!==FALSE) {
1625
+ $k=$this->get($v, $key, FALSE);
1626
+ }
1627
+ if($value!==FALSE) {
1628
+ $v=$this->get($v, $value, FALSE);
1629
+ }
1630
+
1631
+ if($k!==FALSE && $v!==FALSE) {
1632
+ $result[$k]=$v;
1633
+ }
1634
+ }
1635
+ return $result;
1636
+ }
1637
+ public function getText($text, $args) {
1638
+ if($args===FALSE || count($args)==0) {
1639
+ return $text;
1640
+ }
1641
+
1642
+ foreach($args as $k=>$v) {
1643
+ $text=str_replace("{".$k."}", $v, $text);
1644
+ }
1645
+ return $text;
1646
+ }
1647
+ public function arrayExtends($options, $defaults) {
1648
+ global $tcmp;
1649
+ $options=$tcmp->Utils->parseArgs($options, $defaults);
1650
+ foreach ($options as $k=>$v) {
1651
+ if(is_bool($v)) {
1652
+ $v=($v ? 1 : 0);
1653
+ }
1654
+ if (isset($defaults[$k])) {
1655
+ if($this->isAssociativeArray($v)) {
1656
+ $v=$this->arrayExtends($v, $defaults[$k]);
1657
+ } else {
1658
+ $v=$tcmp->Utils->toArray($v);
1659
+ $old=$defaults[$k];
1660
+ $old=$tcmp->Utils->toArray($old);
1661
+ if(!$this->isAssociativeArray($old)) {
1662
+ $v=array_merge($v, $old);
1663
+ $v=array_unique($v);
1664
+ }
1665
+ }
1666
+ } else {
1667
+ $v=$tcmp->Utils->toArray($v);
1668
+ }
1669
+ $options[$k]=$v;
1670
+ }
1671
+ return $options;
1672
+ }
1673
+ //send remote request to our server to store tracking and feedback
1674
+ function remotePost($action, $data = '') {
1675
+ global $tcmp;
1676
+
1677
+ $data['secret']='WYSIWYG';
1678
+ $response = wp_remote_post(TCMP_INTELLYWP_ENDPOINT.'?iwpm_action='.$action, array(
1679
+ 'method'=>'POST'
1680
+ , 'timeout'=>20
1681
+ , 'redirection'=>5
1682
+ , 'httpversion'=>'1.1'
1683
+ , 'blocking'=>TRUE
1684
+ , 'body'=>$data
1685
+ , 'user-agent'=>TCMP_PLUGIN_NAME.'/'.TCMP_PLUGIN_VERSION.'; '.get_bloginfo('url')
1686
+ ));
1687
+ $data = json_decode(wp_remote_retrieve_body($response), TRUE);
1688
+ if (is_wp_error($response) || wp_remote_retrieve_response_code($response) != 200
1689
+ || !isset($data['success']) || !$data['success']
1690
+ ) {
1691
+ $tcmp->Log->error('ERRORS SENDING REMOTE-POST ACTION=%s DUE TO REASON=%s', $action, $response);
1692
+ $data = FALSE;
1693
+ } else {
1694
+ $tcmp->Log->debug('SUCCESSFULLY SENT REMOTE-POST ACTION=%s RESPONSE=%s', $action, $data);
1695
+ }
1696
+ return $data;
1697
+ }
1698
+ function remoteGet($uri, $options) {
1699
+ global $tcmp;
1700
+ $result=FALSE;
1701
+ $uri=$this->addQueryString($options, $uri);
1702
+ //$uri=str_replace('https://', 'http://', $uri);
1703
+
1704
+ $args=array('timeout'=>900, 'sslverify'=>false);
1705
+ $tcmp->Log->debug('REMOTEGET: URI=%s', $uri);
1706
+ $response=FALSE;//wp_remote_get($uri, $args);
1707
+ if ($response!==FALSE && !is_wp_error($response)) {
1708
+ // decode the license data
1709
+ $body=wp_remote_retrieve_body($response);
1710
+ if($body!==FALSE && $body!='') {
1711
+ $tcmp->Log->debug('REMOTEGET: RETRIEVEBODY=%s', $body);
1712
+ $result=json_decode($body);
1713
+ if(!$result) {
1714
+ $tcmp->Log->error('REMOTEGET: UNDECODABLE BODY');
1715
+ if(strpos($body, 'debug')!==FALSE || strpos($body, 'fatal')!==FALSE || strpos($body, 'warning')!==FALSE || strpos($body, 'error')!==FALSE) {
1716
+ $tcmp->Options->pushErrorMessage('XdebugException');
1717
+ }
1718
+ }
1719
+ } else {
1720
+ $tcmp->Log->debug('REMOTEGET: RETRIEVEBODY ERROR');
1721
+ $result=FALSE;
1722
+ }
1723
+ } else {
1724
+ $tcmp->Log->debug('REMOTEGET: RESULT=ERROR');
1725
+ }
1726
+ if($result===FALSE) {
1727
+ $tcmp->Log->debug('file_get_contents: URI=%s', $uri);
1728
+ //$body=file_get_contents($uri);
1729
+ $ch=curl_init();
1730
+ $timeout=900;
1731
+ curl_setopt($ch, CURLOPT_URL, $uri);
1732
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
1733
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
1734
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1735
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
1736
+ $body=curl_exec($ch);
1737
+ curl_close($ch);
1738
+
1739
+ $tcmp->Log->debug('file_get_contents: RETRIEVEBODY=%s', $body);
1740
+ if($body!==FALSE && $body!='') {
1741
+ $tcmp->Log->debug('REMOTEGET: RETRIEVEBODY=%s', $body);
1742
+ $result=json_decode($body);
1743
+ if(!$result) {
1744
+ $tcmp->Log->error('REMOTEGET: UNDECODABLE BODY');
1745
+ if(strpos($body, 'xdebug')!==FALSE) {
1746
+ $tcmp->Options->pushErrorMessage('XdebugException');
1747
+ }
1748
+ }
1749
+ } else {
1750
+ $tcmp->Log->debug('REMOTEGET: RETRIEVEBODY ERROR');
1751
+ $result=FALSE;
1752
+ }
1753
+ }
1754
+ /*if(TRUE || $result===FALSE) {
1755
+ $ch=curl_init();
1756
+ curl_setopt($ch, CURLOPT_URL, $uri);
1757
+ curl_setopt($ch, CURLOPT_HEADER, 0);
1758
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
1759
+ $result=curl_exec($ch);
1760
+ curl_close($ch);
1761
+ if($result!==FALSE && $result!='') {
1762
+ $result=json_decode($result);
1763
+ } else {
1764
+ $result=FALSE;
1765
+ }
1766
+ }*/
1767
+ if(!$result) {
1768
+ $result=FALSE;
1769
+ }
1770
+ return $result;
1771
+ }
1772
+
1773
+ function isAdminUser() {
1774
+ //https://wordpress.org/support/topic/how-to-check-admin-right-without-include-pluggablephp
1775
+ return TRUE;
1776
+ /*
1777
+ if (!function_exists('wp_get_current_user')) {
1778
+ require_once(ABSPATH.'wp-includes/pluggable.php');
1779
+ }
1780
+ return (is_multisite() || current_user_can('manage_options'));
1781
+ */
1782
+ }
1783
+ function isUserLogged() {
1784
+ if (!function_exists('is_user_logged_in')) {
1785
+ require_once(ABSPATH.'wp-includes/pluggable.php');
1786
+ }
1787
+ $result=is_user_logged_in();
1788
+ return $result;
1789
+ }
1790
+ function isPluginPage() {
1791
+ global $tcmp;
1792
+ $page=TCMP_SQS('page');
1793
+ $result=($this->startsWith($page, TCMP_PLUGIN_SLUG));
1794
+ return $result;
1795
+ }
1796
+ function isQsNull($v) {
1797
+ return (is_null($v) || $v===FALSE || $v==='');
1798
+ }
1799
+ function jsonToClass($json, $class) {
1800
+ global $tcmp;
1801
+ $instance=$tcmp->Dao->Utils->getClass($class);
1802
+ if($instance=='') {
1803
+ throw new Exception('CLASS ['.$class.'] DOES NOT EXIST');
1804
+ }
1805
+ $result=FALSE;
1806
+ if(is_bool($json)) {
1807
+ return $json;
1808
+ }
1809
+ if(is_string($json)) {
1810
+ $json=json_decode($json);
1811
+ }
1812
+ if($class=='stdClass') {
1813
+ $result=new stdClass();
1814
+ foreach ($json as $k=>$v) {
1815
+ $result->$k=$v;
1816
+ }
1817
+ return $result;
1818
+ }
1819
+
1820
+ if($tcmp->Utils->isArray($json) && !$tcmp->Utils->isAssociativeArray($json)) {
1821
+ $match=FALSE;
1822
+ $result=array();
1823
+ foreach($json as $v) {
1824
+ $v=$this->jsonToInstance($json, $v);
1825
+ if($v!==FALSE) {
1826
+ $result[]=$v;
1827
+ $match=TRUE;
1828
+ }
1829
+ }
1830
+ if(!$match) {
1831
+ $result=FALSE;
1832
+ }
1833
+ } elseif($tcmp->Utils->isAssociativeArray($json) || is_object($json)) {
1834
+ $result=$this->jsonToInstance($json, $class);
1835
+ }
1836
+ return $result;
1837
+ }
1838
+ private function jsonToInstance($json, $class) {
1839
+ global $tcmp;
1840
+
1841
+ $match=FALSE;
1842
+ $result=FALSE;
1843
+ $columns=$tcmp->Dao->Utils->getAllColumns($class);
1844
+ $instance=$tcmp->Dao->Utils->getClass($class);
1845
+ $instance=new $instance();
1846
+ foreach($json as $property=>$value) {
1847
+ if(isset($columns[$property])) {
1848
+ $column=$columns[$property];
1849
+ if(isset($column['ui-type']) && $column['ui-type']=='array') {
1850
+ $array=array();
1851
+ $rel=$column['rel'];
1852
+ foreach ($value as $k => $v) {
1853
+ $v=$this->jsonToInstance($v, $rel);
1854
+ $array[$k] = $v;
1855
+ }
1856
+ $value=$array;
1857
+ } else {
1858
+ $value=$tcmp->Dao->Utils->decode($class, $property, $value);
1859
+ }
1860
+ }
1861
+ if($tcmp->Utils->set($instance, $property, $value)) {
1862
+ $match=TRUE;
1863
+ }
1864
+ }
1865
+ if($match) {
1866
+ $result=$instance;
1867
+ }
1868
+ return $result;
1869
+ }
1870
+ public function classToJson($instance) {
1871
+ if(!is_object($instance)) {
1872
+ $instance=(array)$instance;
1873
+ }
1874
+ $result=wp_json_encode($instance);
1875
+ return $result;
1876
+ }
1877
+
1878
+ function dateGt($dt1, $dt2) {
1879
+ $dt1=$this->parseDateToTime($dt1);
1880
+ $dt2=$this->parseDateToTime($dt2);
1881
+ return ($dt1>$dt2);
1882
+ }
1883
+ function dateGtEq($dt1, $dt2) {
1884
+ $dt1=$this->parseDateToTime($dt1);
1885
+ $dt2=$this->parseDateToTime($dt2);
1886
+ return ($dt1>=$dt2);
1887
+ }
1888
+ function dateEq($dt1, $dt2) {
1889
+ $dt1=$this->parseDateToTime($dt1);
1890
+ $dt2=$this->parseDateToTime($dt2);
1891
+ return ($dt1==$dt2);
1892
+ }
1893
+ function dateLt($dt1, $dt2) {
1894
+ $dt1=$this->parseDateToTime($dt1);
1895
+ $dt2=$this->parseDateToTime($dt2);
1896
+ return ($dt1<$dt2);
1897
+ }
1898
+ function dateLtEq($dt1, $dt2) {
1899
+ $dt1=$this->parseDateToTime($dt1);
1900
+ $dt2=$this->parseDateToTime($dt2);
1901
+ return ($dt1<=$dt2);
1902
+ }
1903
+ function absDateDiff($dt1, $dt2, $unit='d') {
1904
+ $diff=$this->dateDiff($dt1, $dt2, $unit);
1905
+ $diff=abs($diff);
1906
+ return $diff;
1907
+ }
1908
+ function dateDiff($dt1, $dt2, $unit='d') {
1909
+ $dt1=$this->formatSqlDatetime($dt1);
1910
+ $dt2=$this->formatSqlDatetime($dt2);
1911
+ $dt1=new DateTime($dt1);
1912
+ $dt2=new DateTime($dt2);
1913
+ $diff=$dt1->diff($dt2);
1914
+
1915
+ $result=0;
1916
+ switch ($unit) {
1917
+ case 'Y':
1918
+ case 'y':
1919
+ $result=$diff->y;
1920
+ break;
1921
+ case 'm':
1922
+ $result=$diff->m;
1923
+ break;
1924
+ case 'd':
1925
+ $result=$diff->days;
1926
+ break;
1927
+ case 'H':
1928
+ case 'h':
1929
+ $result=$diff->h;
1930
+ break;
1931
+ case 'n':
1932
+ case 'i':
1933
+ $result=$diff->i;
1934
+ break;
1935
+ case 's':
1936
+ $result=$diff->s;
1937
+ break;
1938
+ }
1939
+ return $result;
1940
+ }
1941
+ public function arrayPush(&$array, $another) {
1942
+ if(!is_array($another)) {
1943
+ array_push($array, $another);
1944
+ } elseif(is_array($another)) {
1945
+ foreach($another as $v) {
1946
+ array_push($array, $v);
1947
+ }
1948
+ }
1949
+ return $array;
1950
+ }
1951
+ public function encodeData($data) {
1952
+ $dataType='';
1953
+ $dataClass='';
1954
+ $text=FALSE;
1955
+ if(is_object($data)) {
1956
+ $dataType='class';
1957
+ $dataClass=get_class($data);
1958
+ $text=$this->classToJson($data);
1959
+ } elseif(is_array($data)) {
1960
+ $dataType='array';
1961
+ if(count($data)>0) {
1962
+ //array of class??
1963
+ $associative=$this->isAssociativeArray($data);
1964
+ foreach($data as $k=>$v) {
1965
+ break;
1966
+ }
1967
+ if(is_object($v)) {
1968
+ $dataType='class';
1969
+ $dataClass=get_class($v);
1970
+ $text=$this->classToJson($data);
1971
+ } else {
1972
+ $text=json_encode($data);
1973
+ }
1974
+ } else {
1975
+ $text=json_encode($data);
1976
+ }
1977
+ } else {
1978
+ $dataType='primitive';
1979
+ $text=json_encode($data);
1980
+ }
1981
+
1982
+ $result=array(
1983
+ 'dataType'=>$dataType
1984
+ , 'dataClass'=>$dataClass
1985
+ , 'data'=>$this->httpEncode($text)
1986
+ );
1987
+ return $result;
1988
+ }
1989
+ public function decodeData($data=array()) {
1990
+ $defaults=array(
1991
+ 'dataType'=>$this->qs('dataType', '')
1992
+ , 'dataClass'=>$this->qs('dataClass', '')
1993
+ , 'data'=>$this->qs('data', '')
1994
+ );
1995
+ $data=$this->parseArgs($data, $defaults);
1996
+ $data['data']=$this->httpDecode($data['data']);
1997
+
1998
+ //$data['data']=str_replace("\\\"", "\"", $data['data']);
1999
+ //$data['data']=str_replace("\\\\", "\\", $data['data']);
2000
+
2001
+ $result=FALSE;
2002
+ switch (strtolower($data['dataType'])) {
2003
+ case 'array':
2004
+ $result=json_decode($data['data'], TRUE);
2005
+ break;
2006
+ case 'class':
2007
+ if(class_exists($data['dataClass']) && $this->startsWith($data['dataClass'], TCMP_PLUGIN_PREFIX)) {
2008
+ $result=$this->jsonToClass($data['data'], $data['dataClass']);
2009
+ } else {
2010
+ $result=json_decode($data['data'], TRUE);
2011
+ }
2012
+ break;
2013
+ default:
2014
+ $result=json_decode($data['data']);
2015
+ break;
2016
+ }
2017
+ return $result;
2018
+ }
2019
+ public function getConstantsValues($class, $prefix='', $glue=FALSE) {
2020
+ $array=$this->getConstants($class, $prefix);
2021
+ $result=array_values($array);
2022
+ if($glue!==FALSE) {
2023
+ $result=implode($glue, $result);
2024
+ }
2025
+ return $result;
2026
+
2027
+ }
2028
+ public function getValue($array, $index, $default=FALSE) {
2029
+ $result=$this->getIndex($array, $index, $default);
2030
+ if($result!==$default) {
2031
+ $result=$result['v'];
2032
+ }
2033
+ return $result;
2034
+ }
2035
+ public function getKey($array, $index, $default=FALSE) {
2036
+ $result=$this->getIndex($array, $index, $default);
2037
+ if($result!==$default) {
2038
+ $result=$result['k'];
2039
+ }
2040
+ return $result;
2041
+ }
2042
+ public function getIndex($array, $index, $default=FALSE) {
2043
+ $result=$default;
2044
+ if(is_array($array) && count($array)>0) {
2045
+ if($this->isAssociativeArray($array)) {
2046
+ $i=0;
2047
+ foreach($array as $k=>$v) {
2048
+ if($index==$i) {
2049
+ $result=array(
2050
+ 'k'=>$k
2051
+ , 'v'=>$v
2052
+ );
2053
+ break;
2054
+ }
2055
+ $i++;
2056
+ }
2057
+ } else {
2058
+ if($index<count($array) && $index>=0) {
2059
+ $result=$array[$index];
2060
+ }
2061
+ }
2062
+ }
2063
+ return $result;
2064
+ }
2065
+ public function isEmpty($v) {
2066
+ if(!$v) {
2067
+ return TRUE;
2068
+ }
2069
+
2070
+ $result=FALSE;
2071
+ if(is_string($v)) {
2072
+ $result=($v=='');
2073
+ } elseif(is_array($v)) {
2074
+ $result=count($v)==0;
2075
+ } elseif(is_object($v)) {
2076
+ $result=TRUE;
2077
+ foreach($v as $k=>$w) {
2078
+ if(!is_null($w) && $w!=='') {
2079
+ $result=FALSE;
2080
+ break;
2081
+ }
2082
+ }
2083
+ }
2084
+ return $result;
2085
+ }
2086
+ public function httpEncode($v) {
2087
+ $v=gzcompress($v);
2088
+ $v=bin2hex($v);
2089
+ return $v;
2090
+ }
2091
+ public function httpDecode($v) {
2092
+ $v=hex2bin($v);
2093
+ $v=gzuncompress($v);
2094
+ return $v;
2095
+ }
2096
+ public function trimHttp($uri) {
2097
+ $uri=str_replace('http://', '', $uri);
2098
+ $uri=str_replace('https://', '', $uri);
2099
+ return $uri;
2100
+ }
2101
+ function getClientIpAddress() {
2102
+ $ipaddress='';
2103
+ if (getenv('HTTP_CLIENT_IP'))
2104
+ $ipaddress=getenv('HTTP_CLIENT_IP');
2105
+ else if(getenv('HTTP_X_FORWARDED_FOR'))
2106
+ $ipaddress=getenv('HTTP_X_FORWARDED_FOR');
2107
+ else if(getenv('HTTP_X_FORWARDED'))
2108
+ $ipaddress=getenv('HTTP_X_FORWARDED');
2109
+ else if(getenv('HTTP_FORWARDED_FOR'))
2110
+ $ipaddress=getenv('HTTP_FORWARDED_FOR');
2111
+ else if(getenv('HTTP_FORWARDED'))
2112
+ $ipaddress=getenv('HTTP_FORWARDED');
2113
+ else if(getenv('REMOTE_ADDR'))
2114
+ $ipaddress=getenv('REMOTE_ADDR');
2115
+ else
2116
+ $ipaddress='UNKNOWN';
2117
+ $ipaddress=($ipaddress == '::1') ? '192.168.0.1' : $ipaddress;
2118
+ return $ipaddress;
2119
+ }
2120
+ public function isMail($mail) {
2121
+ $at=strpos($mail, '@');
2122
+ $dot=strrpos($mail, '.');
2123
+ $result=FALSE;
2124
+ if($at!==FALSE && $dot!==FALSE && $at<$dot) {
2125
+ $result=TRUE;
2126
+ }
2127
+ return $result;
2128
+ }
2129
+ public function getNameFromListArray($array, $id, $default=FALSE) {
2130
+ $result=$default;
2131
+ foreach($array as $v) {
2132
+ if($v['id']==$id) {
2133
+ if(isset($v['text'])) {
2134
+ $result=$v['text'];
2135
+ break;
2136
+ } elseif(isset($v['name'])) {
2137
+ $result=$v['name'];
2138
+ break;
2139
+ }
2140
+ }
2141
+ }
2142
+ return $result;
2143
+ }
2144
+ function bqs($name, $default=FALSE) {
2145
+ $v=$this->qs($name, '');
2146
+ $result=$default;
2147
+ if($v!='') {
2148
+ if(is_numeric($v)) {
2149
+ $v=intval($v);
2150
+ $result=($v>0);
2151
+ } else {
2152
+ $result=$this->isTrue($v);
2153
+ }
2154
+ }
2155
+ return $result;
2156
+ }
2157
+ /**
2158
+ * Get either a Gravatar URL or complete image tag for a specified email address.
2159
+ *
2160
+ * @param string $email The email address
2161
+ * @param string $s Size in pixels, defaults to 80px [ 1 - 2048 ]
2162
+ * @param string $d Default imageset to use [ 404 | mm | identicon | monsterid | wavatar ]
2163
+ * @param string $r Maximum rating (inclusive) [ g | pg | r | x ]
2164
+ * @param boole $img True to return a complete IMG tag False for just the URL
2165
+ * @param array $atts Optional, additional key/value attributes to include in the IMG tag
2166
+ * @return String containing either just a URL or a complete image tag
2167
+ * @source http://gravatar.com/site/implement/images/php/
2168
+ */
2169
+ function getGravatarImage($email, $s=80, $d='mm', $r='g', $img=TRUE, $atts=array()) {
2170
+ if(!is_array($atts)) {
2171
+ $atts=array();
2172
+ }
2173
+ if(!isset($atts['class'])) {
2174
+ $atts['class']='gravatar';
2175
+ }
2176
+ $url='//www.gravatar.com/avatar/';
2177
+ $url.=md5(strtolower(trim($email)));
2178
+ $url.="?s=$s&d=$d&r=$r";
2179
+ if ($img) {
2180
+ $url='<img src="'.$url.'"';
2181
+ foreach ($atts as $key => $val)
2182
+ $url .= ' '.$key.'="'.$val.'"';
2183
+ $url .= ' />';
2184
+ }
2185
+ return $url;
2186
+ }
2187
+ function getGravatarUri($email, $s=80, $d='mm', $r='g', $atts=array()) {
2188
+ $url=$this->getGravatarImage($email, $s, $d, $r, FALSE, $atts);
2189
+ return $url;
2190
+ }
2191
+ function getFunctionName($function) {
2192
+ $result=FALSE;
2193
+ if(is_string($function)) {
2194
+ $result=$function;
2195
+ } elseif(is_array($function)) {
2196
+ $result=$function[1];
2197
+ }
2198
+ return $result;
2199
+ }
2200
+ function functionExists($function) {
2201
+ $result=FALSE;
2202
+ if(is_string($function)) {
2203
+ $result=function_exists($function);
2204
+ } elseif(is_array($function)) {
2205
+ $result=method_exists($function[0], $function[1]);
2206
+ } elseif(is_callable($function)) {
2207
+ $result=TRUE;
2208
+ }
2209
+ return $result;
2210
+ }
2211
+ function functionCall() {
2212
+ $args=func_get_args();
2213
+ if($args===FALSE || count($args)==0) {
2214
+ return;
2215
+ }
2216
+
2217
+ $function=array_shift($args);
2218
+ $result=NULL;
2219
+ if($this->functionExists($function)) {
2220
+ $result=call_user_func_array($function, $args);
2221
+ }
2222
+ return $result;
2223
+ }
2224
+
2225
+ function passwordsEquals($p1, $p2) {
2226
+ if (!function_exists('wp_check_password')) {
2227
+ require_once(ABSPATH.'wp-includes/pluggable.php');
2228
+ }
2229
+ $result=wp_check_password($p1, $p2);
2230
+ return $result;
2231
+ }
2232
+ public function contains($v1, $v2, $ignoreCase=TRUE) {
2233
+ $result=FALSE;
2234
+ if($ignoreCase) {
2235
+ $result=stripos($v1, $v2)!==FALSE;
2236
+ } else {
2237
+ $result=strpos($v1, $v2)!==FALSE;
2238
+ }
2239
+ return $result;
2240
+ }
2241
+ public function getMailTextHtml() {
2242
+ return "text/html";
2243
+ }
2244
+ public function mail($to, $subject, $body, $options=array()) {
2245
+ $subject='[LeadsBridge] '.$subject;
2246
+ $defaults=array(
2247
+ 'html'=>TRUE
2248
+ , 'footer'=>TRUE
2249
+ , 'headers'=>array()
2250
+ , 'noreply'=>TRUE
2251
+ , 'attachments'=>array()
2252
+ );
2253
+ $options=$this->parseArgs($options, $defaults);
2254
+ $to=$this->toArray($to);
2255
+ if($options['html']) {
2256
+ add_filter('wp_mail_content_type', array($this, 'getMailTextHtml'));
2257
+ }
2258
+ if($options['noreply']) {
2259
+ $options['headers'][]='From: LeadsBridge <no-reply@leadsbrige.com>';
2260
+ }
2261
+ if($options['footer'] && $options['html']) {
2262
+ $body .= '<br><hr><a href="'.TCMP_WORDPRESS_SITE.'"><img src="'.TCMP_SITE_IMAGES_URI.'logos/logo-mail.png" /></a>';
2263
+ }
2264
+ $result=FALSE;
2265
+ if(!function_exists('wp_mail')) {
2266
+ include_once('../../../../../../wp-includes/pluggable.php');
2267
+ }
2268
+ if(function_exists('wp_mail')) {
2269
+ if(count($to)>0) {
2270
+ $result=wp_mail($to, $subject, $body
2271
+ , $options['headers'], $options['attachments']);
2272
+ }
2273
+ }
2274
+ return $result;
2275
+ }
2276
+ /*public function formSubmit($action, $method='POST', $data=array(), $options=array()) {
2277
+ $defaults=array('json'=>FALSE);
2278
+ $options=$this->parseArgs($options, $defaults);
2279
+
2280
+ $postData=http_build_query($data);
2281
+ $curl=curl_init();
2282
+ curl_setopt($curl, CURLOPT_URL, $action);
2283
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
2284
+ curl_setopt($curl, CURLOPT_POST, strtolower($method)=='post');
2285
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
2286
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
2287
+ $result=curl_exec($curl);
2288
+ curl_close($curl);
2289
+ if($result!==FALSE && $result!=='' && $options['json']) {
2290
+ $result=json_decode($result, TRUE);
2291
+ }
2292
+ return $result;
2293
+ }*/
2294
+
2295
+ private function getHtmlCode($value) {
2296
+ $value=str_replace('\"', '', $value);
2297
+ $value=str_replace('"', '', $value);
2298
+ return $value;
2299
+ }
2300
+ public function parseHtmlForm($html) {
2301
+ $data=array(
2302
+ 'action'=>''
2303
+ , 'method'=>'GET'
2304
+ , 'fields'=>array()
2305
+ );
2306
+ $result=FALSE;
2307
+
2308
+ $previous=error_reporting();
2309
+ error_reporting($previous^E_WARNING);
2310
+
2311
+ $doc=new DOMDocument();
2312
+ if ($doc->loadHTML($html)) {
2313
+ $xpath=new DOMXPath($doc);
2314
+ $form=$xpath->query('//form');
2315
+ if ($form->length > 0) {
2316
+ $result=TRUE;
2317
+ $data['action']=$this->getHtmlCode($form->item(0)->getAttribute('action'));
2318
+ $data['method']=$this->getHtmlCode($form->item(0)->getAttribute('method'));
2319
+ if($data['method']===FALSE || $data['method']=='') {
2320
+ $data['method']='GET';
2321
+ }
2322
+ $data['method']=strtoupper($data['method']);