Tracking Code Manager - Version 1.4

Version Description

  • 06/04/2015
  • Created the FREE version following Wordpress specs. Branching the PRO version available to buy using website http://www.intellywp.com/tracking-code-manager
Download this release

Release Info

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

Version 1.4

Files changed (98) hide show
  1. assets/css/style.css +83 -0
  2. assets/deps/select2-3.5.2/.gitignore +2 -0
  3. assets/deps/select2-3.5.2/CONTRIBUTING.md +107 -0
  4. assets/deps/select2-3.5.2/LICENSE +18 -0
  5. assets/deps/select2-3.5.2/README.md +114 -0
  6. assets/deps/select2-3.5.2/bower.json +8 -0
  7. assets/deps/select2-3.5.2/component.json +66 -0
  8. assets/deps/select2-3.5.2/composer.json +29 -0
  9. assets/deps/select2-3.5.2/package.json +20 -0
  10. assets/deps/select2-3.5.2/release.sh +79 -0
  11. assets/deps/select2-3.5.2/select2-bootstrap.css +87 -0
  12. assets/deps/select2-3.5.2/select2-spinner.gif +0 -0
  13. assets/deps/select2-3.5.2/select2.css +704 -0
  14. assets/deps/select2-3.5.2/select2.jquery.json +36 -0
  15. assets/deps/select2-3.5.2/select2.js +3541 -0
  16. assets/deps/select2-3.5.2/select2.min.js +23 -0
  17. assets/deps/select2-3.5.2/select2.png +0 -0
  18. assets/deps/select2-3.5.2/select2_locale_ar.js +19 -0
  19. assets/deps/select2-3.5.2/select2_locale_az.js +20 -0
  20. assets/deps/select2-3.5.2/select2_locale_bg.js +20 -0
  21. assets/deps/select2-3.5.2/select2_locale_ca.js +19 -0
  22. assets/deps/select2-3.5.2/select2_locale_cs.js +51 -0
  23. assets/deps/select2-3.5.2/select2_locale_da.js +19 -0
  24. assets/deps/select2-3.5.2/select2_locale_de.js +18 -0
  25. assets/deps/select2-3.5.2/select2_locale_el.js +19 -0
  26. assets/deps/select2-3.5.2/select2_locale_en.js.template +20 -0
  27. assets/deps/select2-3.5.2/select2_locale_es.js +19 -0
  28. assets/deps/select2-3.5.2/select2_locale_et.js +19 -0
  29. assets/deps/select2-3.5.2/select2_locale_eu.js +45 -0
  30. assets/deps/select2-3.5.2/select2_locale_fa.js +21 -0
  31. assets/deps/select2-3.5.2/select2_locale_fi.js +30 -0
  32. assets/deps/select2-3.5.2/select2_locale_fr.js +18 -0
  33. assets/deps/select2-3.5.2/select2_locale_gl.js +45 -0
  34. assets/deps/select2-3.5.2/select2_locale_he.js +19 -0
  35. assets/deps/select2-3.5.2/select2_locale_hr.js +24 -0
  36. assets/deps/select2-3.5.2/select2_locale_hu.js +17 -0
  37. assets/deps/select2-3.5.2/select2_locale_id.js +19 -0
  38. assets/deps/select2-3.5.2/select2_locale_is.js +17 -0
  39. assets/deps/select2-3.5.2/select2_locale_it.js +17 -0
  40. assets/deps/select2-3.5.2/select2_locale_ja.js +17 -0
  41. assets/deps/select2-3.5.2/select2_locale_ka.js +19 -0
  42. assets/deps/select2-3.5.2/select2_locale_ko.js +19 -0
  43. assets/deps/select2-3.5.2/select2_locale_lt.js +26 -0
  44. assets/deps/select2-3.5.2/select2_locale_lv.js +19 -0
  45. assets/deps/select2-3.5.2/select2_locale_mk.js +19 -0
  46. assets/deps/select2-3.5.2/select2_locale_ms.js +19 -0
  47. assets/deps/select2-3.5.2/select2_locale_nb.js +22 -0
  48. assets/deps/select2-3.5.2/select2_locale_nl.js +17 -0
  49. assets/deps/select2-3.5.2/select2_locale_pl.js +54 -0
  50. assets/deps/select2-3.5.2/select2_locale_pt-BR.js +18 -0
  51. assets/deps/select2-3.5.2/select2_locale_pt-PT.js +17 -0
  52. assets/deps/select2-3.5.2/select2_locale_ro.js +17 -0
  53. assets/deps/select2-3.5.2/select2_locale_rs.js +19 -0
  54. assets/deps/select2-3.5.2/select2_locale_ru.js +23 -0
  55. assets/deps/select2-3.5.2/select2_locale_sk.js +50 -0
  56. assets/deps/select2-3.5.2/select2_locale_sv.js +19 -0
  57. assets/deps/select2-3.5.2/select2_locale_th.js +19 -0
  58. assets/deps/select2-3.5.2/select2_locale_tr.js +19 -0
  59. assets/deps/select2-3.5.2/select2_locale_ug-CN.js +16 -0
  60. assets/deps/select2-3.5.2/select2_locale_uk.js +25 -0
  61. assets/deps/select2-3.5.2/select2_locale_vi.js +20 -0
  62. assets/deps/select2-3.5.2/select2_locale_zh-CN.js +16 -0
  63. assets/deps/select2-3.5.2/select2_locale_zh-TW.js +16 -0
  64. assets/deps/select2-3.5.2/select2x2.png +0 -0
  65. assets/images/email.png +0 -0
  66. assets/images/heart.png +0 -0
  67. assets/images/internet.png +0 -0
  68. assets/images/tick.png +0 -0
  69. assets/images/twitter.png +0 -0
  70. assets/js/tcm-autocomplete.js +49 -0
  71. includes/actions.php +69 -0
  72. includes/admin/about.php +38 -0
  73. includes/admin/editor.php +243 -0
  74. includes/admin/feedback.php +45 -0
  75. includes/admin/manager.php +133 -0
  76. includes/admin/metabox.php +160 -0
  77. includes/admin/settings.php +44 -0
  78. includes/class-TCM-check.php +112 -0
  79. includes/class-TCM-cron.php +83 -0
  80. includes/class-TCM-form.php +298 -0
  81. includes/class-TCM-language.php +125 -0
  82. includes/class-TCM-logger.php +80 -0
  83. includes/class-TCM-manager.php +320 -0
  84. includes/class-TCM-options.php +266 -0
  85. includes/class-TCM-tracking.php +189 -0
  86. includes/class-TCM-utils.php +181 -0
  87. includes/core.php +26 -0
  88. includes/install.php +12 -0
  89. includes/uninstall.php +9 -0
  90. languages/TCM.txt +74 -0
  91. readme.txt +100 -0
  92. screenshot-1.png +0 -0
  93. screenshot-2.png +0 -0
  94. screenshot-3.png +0 -0
  95. screenshot-4.png +0 -0
  96. screenshot-5.png +0 -0
  97. screenshot-6.png +0 -0
  98. tracking-code-manager.php +211 -0
assets/css/style.css ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ._tcm {
2
+ background-color: #efc439;
3
+ border-radius: 2px;
4
+ color: #fff;
5
+ display: inline-block;
6
+ font-size: 12px;
7
+ padding: 0 2px;
8
+ line-height: 14px;
9
+ vertical-align: baseline;
10
+ }
11
+
12
+ .tcm-tag {
13
+ display: inline-block;
14
+ line-height: 13px;
15
+ padding: 0 3px;
16
+ color: white;
17
+ font-size: 10px;
18
+ font-weight: normal;
19
+ width:25px;
20
+ margin-top:3px;
21
+ margin-right:5px;
22
+ text-align:center;
23
+ -webkit-border-radius: 2px;
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;
49
+ background-color:#f8f8f8;
50
+ width:550px;
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-select {
78
+
79
+ }
80
+ .tcm-form-newline {
81
+ clear:both;
82
+ margin-bottom:5px;
83
+ }
assets/deps/select2-3.5.2/.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
1
+ .idea
2
+
assets/deps/select2-3.5.2/CONTRIBUTING.md ADDED
@@ -0,0 +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
assets/deps/select2-3.5.2/LICENSE ADDED
@@ -0,0 +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.
assets/deps/select2-3.5.2/README.md ADDED
@@ -0,0 +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.
assets/deps/select2-3.5.2/bower.json ADDED
@@ -0,0 +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
+ }
assets/deps/select2-3.5.2/component.json ADDED
@@ -0,0 +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
+ }
assets/deps/select2-3.5.2/composer.json ADDED
@@ -0,0 +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
+ }
assets/deps/select2-3.5.2/package.json ADDED
@@ -0,0 +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
+ }
assets/deps/select2-3.5.2/release.sh ADDED
@@ -0,0 +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"
assets/deps/select2-3.5.2/select2-bootstrap.css ADDED
@@ -0,0 +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
+ }
assets/deps/select2-3.5.2/select2-spinner.gif ADDED
Binary file
assets/deps/select2-3.5.2/select2.css ADDED
@@ -0,0 +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
+ }
assets/deps/select2-3.5.2/select2.jquery.json ADDED
@@ -0,0 +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
+ }
assets/deps/select2-3.5.2/select2.js ADDED
@@ -0,0 +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));
assets/deps/select2-3.5.2/select2.min.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2.png ADDED
Binary file
assets/deps/select2-3.5.2/select2_locale_ar.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_az.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_bg.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_ca.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_cs.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_da.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_de.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_el.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_en.js.template ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_es.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_et.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_eu.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_fa.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_fi.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_fr.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_gl.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_he.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_hr.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_hu.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_id.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_is.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_it.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_ja.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_ka.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_ko.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_lt.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_lv.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_mk.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_ms.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_nb.js ADDED
@@ -0,0 +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
+
assets/deps/select2-3.5.2/select2_locale_nl.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_pl.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_pt-BR.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_pt-PT.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_ro.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_rs.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_ru.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_sk.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_sv.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_th.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_tr.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_ug-CN.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_uk.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_vi.js ADDED
@@ -0,0 +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
+
assets/deps/select2-3.5.2/select2_locale_zh-CN.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2_locale_zh-TW.js ADDED
@@ -0,0 +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);
assets/deps/select2-3.5.2/select2x2.png ADDED
Binary file
assets/images/email.png ADDED
Binary file
assets/images/heart.png ADDED
Binary file
assets/images/internet.png ADDED
Binary file
assets/images/tick.png ADDED
Binary file
assets/images/twitter.png ADDED
Binary file
assets/js/tcm-autocomplete.js ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ });
includes/actions.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ }
includes/admin/about.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ function tcm_ui_rate_us() {
3
+ $rate_text = sprintf(__('Thank you for using <a href="%1$s" target="_blank">Easy Digital Downloads</a>! Please <a href="%2$s" target="_blank">rate us</a> on <a href="%2$s" target="_blank">WordPress.org</a>', 'edd'),
4
+ 'https://easydigitaldownloads.com',
5
+ 'https://wordpress.org/support/view/plugin-reviews/easy-digital-downloads?rate=5#postform'
6
+ );
7
+ return $rate_text;
8
+ }
9
+
10
+ function tcm_ui_about() {
11
+ global $tcm;
12
+
13
+ $tcm->Options->pushSuccessMessage($tcm->Lang->L('AboutNotice'));
14
+ $tcm->Options->writeMessages();
15
+
16
+ ?>
17
+ <div><?php $tcm->Lang->P('AboutText')?></div>
18
+ <style>
19
+ ul li {
20
+ padding:2px;
21
+ }
22
+ </style>
23
+ <ul>
24
+ <li>
25
+ <img style="float:left; margin-right:10px;" src="<?php echo TCM_PLUGIN_IMAGES?>email.png" />
26
+ <a href="mailto:aleste@intellywp.com">Email aleste@intellywp.com</a>
27
+ </li>
28
+ <li>
29
+ <img style="float:left; margin-right:10px;" src="<?php echo TCM_PLUGIN_IMAGES?>twitter.png" />
30
+ <a href="https://twitter.com/intellywp" target="_new">Twitter @intellywp</a>
31
+ </li>
32
+ <li>
33
+ <img style="float:left; margin-right:10px;" src="<?php echo TCM_PLUGIN_IMAGES?>internet.png" />
34
+ <a href="http://www.intellywp.com" target="_new">Website intellywp.com</a>
35
+ </li>
36
+ </ul>
37
+ <?php
38
+ }
includes/admin/editor.php ADDED
@@ -0,0 +1,243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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);
118
+ if(show) {
119
+ $selector.show();
120
+ } else {
121
+ $selector.hide();
122
+ }
123
+ }
124
+
125
+ /*jQuery(".tcmTags").select2({
126
+ placeholder: "Type here..."
127
+ , theme: "classic"
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() {
144
+ tcmCheckVisible();
145
+ });
146
+ tcmCheckVisible();
147
+ });
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('Except 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
+ $q = array_merge($q, array('post', 'page'));
207
+ sort($q);
208
+ $q=implode(', ', $q);
209
+
210
+ while($tcm->Lang->H('Notice.ProFeature'.$i)) { ?>
211
+ <div style="clear:both; margin-top: 2px;"></div>
212
+ <div style="float:left; vertical-align:middle; height:24px; margin-right:5px;">
213
+ <img src="<?php echo TCM_PLUGIN_IMAGES?>tick.png" />
214
+ </div>
215
+ <div style="float:left; vertical-align:middle; height:24px;">
216
+ <?php $tcm->Lang->P('Notice.ProFeature'.$i, $q)?>
217
+ </div>
218
+ <?php ++$i;
219
+ }
220
+ ?>
221
+ <div style="clear:both;"></div>
222
+ <div style="height:10px;"></div>
223
+ </div>
224
+ <br/>
225
+ <?php }
226
+
227
+ function tcm_formOptions($prefix, $snippet) {
228
+ global $tcm;
229
+
230
+ $types=$tcm->Utils->query(TCM_QUERY_POST_TYPES);
231
+ foreach($types as $v) {
232
+ $args = array('post_type' => $v['name'], 'all' => TRUE);
233
+ $values = $tcm->Utils->query(TCM_QUERY_POSTS_OF_TYPE, $args);
234
+
235
+ $keyActive=$prefix.'PostsOfType_'.$v['name'].'_Active';
236
+ $keyArray=$prefix.'PostsOfType_'.$v['name'];
237
+ if($snippet[$keyActive]==0 && count($snippet[$keyArray])==0) {
238
+ //when enabled default selected -1
239
+ $snippet[$keyArray]=array(-1);
240
+ }
241
+ $tcm->Form->checkSelect($keyActive, $keyArray, $snippet, $values);
242
+ }
243
+ }
includes/admin/feedback.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
8
+ if($hide) {
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)) {
18
+ $text.='&nbsp;{'.$values.'}';
19
+ } elseif(count($values)>0) {
20
+ $what=implode(',', $values);
21
+ if($what!='') {
22
+ $text.='&nbsp;['.$what.']';
23
+ }
24
+ }
25
+ }
26
+ }
27
+ echo $text;
28
+ ?>
29
+ </td>
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->qs('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
+ } else if($id!='') {
54
+ $snippet=$tcm->Manager->get($id);
55
+ $tcm->Options->pushSuccessMessage('CodeUpdateNotice', $id, $snippet['name']);
56
+ }
57
+
58
+ $tcm->Options->writeMessages();
59
+ tcm_ui_free_notice();
60
+
61
+ //controllo che faccio per essere retrocompatibile con la prima versione
62
+ //dove non avevo un id e salvavo tutto con il con il nome quindi una stringa
63
+ $snippets=$tcm->Manager->keys();
64
+ foreach($snippets as $v) {
65
+ $snippet=$tcm->Manager->get($v, FALSE, TRUE);
66
+ if(!$snippet) {
67
+ $tcm->Manager->remove($v);
68
+ } elseif(!is_numeric($v)) {
69
+ $tcm->Manager->remove($v);
70
+ $tcm->Manager->put('', $snippet);
71
+ }
72
+ }
73
+ $snippets=$tcm->Manager->values();
74
+ if (count($snippets)>0) { ?>
75
+ <div style="float:left;">
76
+ <form method="get" action="" style="margin:5px;" class="alignright">
77
+ <input type="hidden" name="page" value="<?php echo TCM_PLUGIN_NAME?>" />
78
+ <input type="hidden" name="tab" value="<?php echo TCM_TAB_EDITOR?>" />
79
+ <input type="submit" class="button-primary" value="<?php $tcm->Lang->P('Button.Add')?>" />
80
+ </form>
81
+ <form method="get" style="margin:5px;" class="alignright" action="<?php echo TCM_PAGE_PREMIUM?>">
82
+ <input type="submit" class="button" value="<?php $tcm->Lang->P('Button.BuyPRO')?>" />
83
+ </form>
84
+ </div>
85
+ <div style="clear:both;"></div>
86
+
87
+ <style>
88
+ .widefat th {
89
+ font-weight: bold!important;
90
+ }
91
+ </style>
92
+ <table class="widefat fixed" style="width:850px;">
93
+ <thead>
94
+ <tr>
95
+ <th><?php $tcm->Lang->P('Name')?></th>
96
+ <th><?php $tcm->Lang->P('Position')?></th>
97
+ <th style="text-align:center;"><?php $tcm->Lang->P('Active?')?></th>
98
+ <th style="text-align:center;"><?php $tcm->Lang->P('Each pages?')?></th>
99
+ <th style="text-align:center;"><?php $tcm->Lang->P('Count')?></th>
100
+ <th style="text-align:center;"><?php $tcm->Lang->P('Actions')?></th>
101
+ </tr>
102
+ </thead>
103
+ <tbody>
104
+ <?php foreach ($snippets as $snippet) { ?>
105
+ <tr>
106
+ <td><?php echo $snippet['name']?></td>
107
+ <td><?php $tcm->Lang->P('Editor.position.'.$snippet['position'])?></td>
108
+ <?php
109
+ tcm_ui_manager_column($snippet['active']);
110
+
111
+ $hide=!$snippet['active'];
112
+ tcm_ui_manager_column($snippet['includeEverywhereActive'], NULL, $hide);
113
+ ?>
114
+ <td style="text-align:center;"><?php echo $snippet['codesCount']?></td>
115
+ <td style="text-align:center;">
116
+ <a href="<?php echo TCM_TAB_EDITOR_URI?>&id=<?php echo $snippet['id'] ?>">
117
+ <?php echo $tcm->Lang->L('Edit')?>
118
+ </a>
119
+ &nbsp;|&nbsp;
120
+ <span class="trash">
121
+ <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'] ?>">
122
+ <?php echo $tcm->Lang->L('Delete')?>
123
+ </a>
124
+ </span>
125
+ </td>
126
+ </tr>
127
+ <?php } ?>
128
+ </tbody>
129
+ </table>
130
+ <?php } else { ?>
131
+ <h2><?php $tcm->Lang->P('EmptyTrackingList', TCM_TAB_EDITOR_URI)?></h2>
132
+ <?php } ?>
133
+ <?php }
includes/admin/metabox.php ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ $snippetsIds=$tcm->Manager->keys();
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
+ foreach($snippetsIds as $id) {
19
+ $snippet=$tcm->Manager->get($id);
20
+ $text=$snippet['name'];
21
+ $checked='';
22
+ if(in_array($id, $ids)) {
23
+ $checked=' checked';
24
+ $active=FALSE;
25
+ if($snippet['active']) {
26
+ $postType=$post->post_type;
27
+ $active=$snippet['includePostsOfType_'.$postType.'_Active']>0;
28
+ }
29
+ $text='<b style="color:'.($active ? 'green' : 'red').';">'.$text.'</b>';
30
+ }
31
+ ?>
32
+ <input type="checkbox" name="tcm_ids[]" value="<?php echo $id?>" <?php echo $checked ?> />
33
+ <a href="<?php echo TCM_TAB_EDITOR_URI?>&id=<?php echo $id?>" target="_blank"><?php echo $text?></a>
34
+ <br/>
35
+ <?php } ?>
36
+ </div>
37
+
38
+ <br/>
39
+ <?php if($tcm->Manager->rc()>0) { ?>
40
+ <div>
41
+ <label for="tcm_name">...<?php $tcm->Lang->P('or add a name')?></label>
42
+ <br/>
43
+ <input type="text" name="tcm_name" value="" style="width:100%"/>
44
+ </div>
45
+ <div>
46
+ <label for="code"><?php $tcm->Lang->P('and paste HTML code here')?></label>
47
+ <br/>
48
+ <textarea dir="ltr" dirname="ltr" name="tcm_code" rows="10" style="font-family:Monaco,'Courier New',Courier,monospace;font-size:12px;width:100%;color:#555;background-color: #f8f8f8;"></textarea>
49
+ </div>
50
+ <?php } else { ?>
51
+ <span style="color:red;font-weight:bold;"><?php $tcm->Lang->P('FreeLicenseReached')?></span>
52
+ <?php }
53
+ }
54
+
55
+ //si aggancia per creare i metabox in post e page
56
+ add_action('add_meta_boxes', 'tcm_add_meta_box');
57
+ function tcm_add_meta_box() {
58
+ global $tcm;
59
+
60
+ $free=array('post', 'page');
61
+ $options=$tcm->Options->getMetaboxPostTypes();
62
+ $screens=array();
63
+ foreach($options as $k=>$v) {
64
+ if(intval($v)>0) {
65
+ $screens[]=$k;
66
+ }
67
+ }
68
+ if(count($screens)>0) {
69
+ foreach ($screens as $screen) {
70
+ add_meta_box(
71
+ 'tcm_sectionid'
72
+ , $tcm->Lang->L('Tracking Code by IntellyWP')
73
+ , 'tcm_ui_metabox'
74
+ , $screen
75
+ , 'side'
76
+ );
77
+ }
78
+ }
79
+ }
80
+ //si aggancia a quando un post viene salvato per salvare anche gli altri dati del metabox
81
+ add_action('save_post', 'tcm_save_meta_box_data');
82
+ function tcm_save_meta_box_data($postId) {
83
+ global $tcm;
84
+
85
+ $postType=$_POST['post_type'];
86
+ //in case of custom post type edit_ does not exist
87
+ //if (!current_user_can('edit_'.$postType, $postId)) {
88
+ // return;
89
+ //}
90
+
91
+ // If this is an autosave, our form has not been submitted, so we don't want to do anything.
92
+ if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
93
+ return;
94
+ }
95
+ if (!isset($_POST['tcm_meta_box_nonce'])) {
96
+ return;
97
+ }
98
+ // Verify that the nonce is valid.
99
+ if (!wp_verify_nonce( $_POST['tcm_meta_box_nonce'], 'tcm_meta_box')) {
100
+ return;
101
+ }
102
+
103
+ $previousIds=explode(',', $tcm->Utils->qs('tcm_previous_ids'));
104
+ $currentIds=$tcm->Utils->qs('tcm_ids', array());
105
+ $keyArray='PostsOfType_'.$postType;
106
+ $keyActive=$keyArray.'_Active';
107
+
108
+ if($previousIds!=$currentIds) {
109
+ //first remove by ids from old snippets
110
+ foreach($previousIds as $id) {
111
+ $id=intval($id);
112
+ if($id>0 && !in_array($id, $currentIds)) {
113
+ $snippet=$tcm->Manager->get($id);
114
+ if($snippet!=NULL) {
115
+ //remove my id from post type includes
116
+ $snippet['include'.$keyArray] = array_diff($snippet['include'.$keyArray], array($postId));
117
+ $snippet['include'.$keyArray] = array_unique($snippet['include'.$keyArray]);
118
+ $snippet['include'.$keyActive]=(count($snippet['include'.$keyArray])>0 ? 1 : 0);
119
+ //include it in post type exception
120
+ $snippet['except'.$keyArray] = array_merge($snippet['except'.$keyArray], array($postId));
121
+ $snippet['except'.$keyArray] = array_unique($snippet['except'.$keyArray]);
122
+ $snippet['except'.$keyActive]=1;
123
+ }
124
+ $tcm->Manager->put($id, $snippet);
125
+ }
126
+ }
127
+ //after insert by id in the snippets selected
128
+ foreach($currentIds as $id) {
129
+ $id=intval($id);
130
+ if($id>0 && !in_array($id, $previousIds)) {
131
+ $snippet = $tcm->Manager->get($id);
132
+ if ($snippet) {
133
+ //include my id in post type includes
134
+ $snippet['include'.$keyArray] = array_merge($snippet['include'.$keyArray], array($postId));
135
+ $snippet['include'.$keyArray] = array_unique($snippet['include'.$keyArray]);
136
+ $snippet['include'.$keyActive]=1;
137
+ //remove it from post type exception
138
+ $snippet['except'.$keyArray] = array_diff($snippet['except'.$keyArray], array($postId));
139
+ $snippet['except'.$keyArray] = array_unique($snippet['except'.$keyArray]);
140
+ $snippet['except'.$keyActive]=(count($snippet['except'.$keyArray])>0 ? 1 : 0);
141
+ }
142
+ $tcm->Manager->put($id, $snippet);
143
+ }
144
+ }
145
+ }
146
+
147
+ $name=stripslashes($tcm->Utils->qs('tcm_name'));
148
+ $code=$tcm->Utils->qs('tcm_code');
149
+ if($name!='' && $code!='' && !$tcm->Manager->exists($name) && $tcm->Manager->rc()>0) {
150
+ $snippet=array(
151
+ 'active'=>1
152
+ , 'name'=>$name
153
+ , 'code'=>$code
154
+ );
155
+ $snippet['include'.$keyActive]=1;
156
+ $snippet['include'.$keyArray]=array($postId);
157
+ $snippet=$tcm->Manager->put('', $snippet);
158
+ $tcm->Logger->debug("NEW SNIPPET REGISTRED=%s", $snippet);
159
+ }
160
+ }
includes/admin/settings.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ }
includes/class-TCM-check.php ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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() {
14
+ $this->data=array_merge($_POST, $_GET);
15
+ }
16
+
17
+ public function is($name, $value, $ignoreCase=TRUE) {
18
+ $result=FALSE;
19
+ if(isset($this->data[$name])) {
20
+ if($ignoreCase) {
21
+ $result=(strtolower($this->data[$name])==strtolower($value));
22
+ } else {
23
+ $result=($this->data[$name]==$value);
24
+ }
25
+ }
26
+ return $result;
27
+ }
28
+ public function of($name, $default='') {
29
+ $result=$default;
30
+ if(isset($this->data[$name])) {
31
+ $result=$this->data[$name];
32
+ }
33
+ return $result;
34
+ }
35
+ public function nonce($action, $nonce='_wpnonce') {
36
+ if(isset($_REQUEST[$nonce])) {
37
+ $nonce=$_REQUEST[$nonce];
38
+ }
39
+ return wp_verify_nonce($nonce, $action);
40
+ }
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;
55
+ }
56
+
57
+ public function value($name) {
58
+ $result='';
59
+ if(isset($this->data[$name])) {
60
+ $result=sanitize_text_field($this->data[$name]);
61
+ }
62
+ if($result=='') {
63
+ $this->error($name);
64
+ }
65
+ $this->data[$name]=$result;
66
+ return $result;
67
+ }
68
+ public function values($name) {
69
+ $result=array();
70
+ if(is_string($name)) {
71
+ $name=explode(',', $name);
72
+ }
73
+ foreach($name as $v) {
74
+ $result[]=$this->value(trim($v));
75
+ }
76
+ return $result;
77
+ }
78
+ public function email($name) {
79
+ $result=$this->value($name);
80
+ if($result!='') {
81
+ $result=sanitize_email($result);
82
+ if(!is_email($result)) {
83
+ $this->error($name);
84
+ }
85
+ }
86
+ $this->data[$name]=$result;
87
+ return $result;
88
+ }
89
+ public function float($name) {
90
+ $result=$this->value($name);
91
+ if($result!='' && !is_float($result)) {
92
+ $this->error($name);
93
+ }
94
+ $result=floatval($result);
95
+ $this->data[$name]=$result;
96
+ return $result;
97
+ }
98
+ public function integer($name) {
99
+ $result=$this->value($name);
100
+ if($result!='' && !is_int($result)) {
101
+ $this->error($name);
102
+ }
103
+ $result=intval($result);
104
+ $this->data[$name]=$result;
105
+ return $result;
106
+ }
107
+
108
+ public function hasErrors() {
109
+ global $tcm;
110
+ return $tcm->Options->hasErrorMessages();
111
+ }
112
+ }
includes/class-TCM-cron.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,298 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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-logger.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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) {
20
+ array_push($this->context, $context);
21
+ }
22
+ public function popContext() {
23
+ array_pop($this->context);
24
+ }
25
+
26
+ public function fatal($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
27
+ $what=$this->write('[FATAL]', $message, $v1, $v2, $v3, $v4, $v5);
28
+ die($what);
29
+ }
30
+ public function debug($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
31
+ $this->write('[DEBUG]', $message, $v1, $v2, $v3, $v4, $v5);
32
+ }
33
+ public function info($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
34
+ $this->write('[INFO] ', $message, $v1, $v2, $v3, $v4, $v5);
35
+ }
36
+ public function error($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
37
+ $this->write('[ERROR]', $message, $v1, $v2, $v3, $v4, $v5);
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) {
48
+ global $tcm;
49
+
50
+ $text=sprintf($message
51
+ , $this->dump($v1)
52
+ , $this->dump($v2)
53
+ , $this->dump($v3)
54
+ , $this->dump($v4)
55
+ , $this->dump($v5));
56
+ $message=date("d/m/Y H:i:s")." ".$verbosity." ";
57
+ if(count($this->context)>0) {
58
+ $message.='{'.$this->context[count($this->context)-1].'} ';
59
+ }
60
+ $message="\n".$message.$text;
61
+ if(!$tcm->Options->isLoggerEnable()) {
62
+ return $message;
63
+ }
64
+
65
+ $hasErrors=false;
66
+ $filename=TCM_PLUGIN_ROOT."logs/".$this->name."_".date("Ym").".txt";
67
+ if (!$handle = fopen($filename, 'a')) {
68
+ $hasErrors=true;
69
+ }
70
+
71
+ if(!$hasErrors && fwrite($handle, $message)===FALSE) {
72
+ $hasErrors=true;
73
+ }
74
+
75
+ if(!$hasErrors) {
76
+ fclose($handle);
77
+ }
78
+ return $message;
79
+ }
80
+ }
includes/class-TCM-manager.php ADDED
@@ -0,0 +1,320 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ if (isset($snippets[$name])) {
16
+ $result=$snippets[$name];
17
+ }
18
+ return $result;
19
+ }
20
+
21
+ //get a code snippet
22
+ public function get($id, $new = FALSE) {
23
+ global $tcm;
24
+
25
+ $snippet=$tcm->Options->getSnippet($id);
26
+ if (!$snippet && $new) {
27
+ $snippet=array();
28
+ $snippet['active']=1;
29
+ $snippet['includeEverywhereActive']=1;
30
+ }
31
+
32
+ $snippet=$this->sanitize($id, $snippet);
33
+ return $snippet;
34
+ }
35
+
36
+ private function sanitize($id, $snippet) {
37
+ global $tcm;
38
+ if($snippet==NULL || !is_array($snippet)) return;
39
+
40
+ $defaults=array(
41
+ 'id'=>$id
42
+ , 'active'=>0
43
+ , 'name'=>''
44
+ , 'code'=>''
45
+ , 'position'=>TCM_POSITION_HEAD
46
+ , 'includeEverywhereActive'=>0
47
+ );
48
+
49
+ $types=$tcm->Utils->query(TCM_QUERY_POST_TYPES);
50
+ foreach($types as $v) {
51
+ $defaults['includePostsOfType_'.$v['name'].'_Active']=0;
52
+ $defaults['includePostsOfType_'.$v['name']]=array();
53
+ $defaults['exceptPostsOfType_'.$v['name'].'_Active']=0;
54
+ $defaults['exceptPostsOfType_'.$v['name']]=array();
55
+ }
56
+ $snippet=$tcm->Utils->parseArgs($snippet, $defaults);
57
+ //$snippet['includeLastPosts'] = intval($snippet['includeLastPosts']);
58
+
59
+ foreach ($snippet as $k => $v) {
60
+ if (stripos($k, 'active') !== FALSE) {
61
+ $snippet[$k]=intval($v);
62
+ } elseif (is_array($v)) {
63
+ switch ($k) {
64
+ /*
65
+ case 'includePostsTypes':
66
+ case 'excludePostsTypes':
67
+ //keys are string and not number
68
+ $result = $this->uarray($snippet, $k, FALSE);
69
+ break;
70
+ */
71
+ default:
72
+ //keys are number
73
+ $result = $this->uarray($snippet, $k, TRUE);
74
+ break;
75
+ }
76
+ }
77
+ }
78
+ $snippet['code']=trim($snippet['code']);
79
+ $snippet['position']=intval($snippet['position']);
80
+
81
+ $code=strtolower($snippet['code']);
82
+ $cnt=substr_count($code, '<iframe')+substr_count($code, '<script');
83
+ if($cnt<=0) {
84
+ $cnt=1;
85
+ }
86
+ $snippet['codesCount']=$cnt;
87
+ return $snippet;
88
+ }
89
+ private function uarray($snippet, $key, $isInteger = TRUE) {
90
+ $array = $snippet[$key];
91
+ if (!is_array($array)) {
92
+ $array = explode(',', $array);
93
+ }
94
+
95
+ if ($isInteger) {
96
+ for ($i = 0; $i < count($array); $i++) {
97
+ $array[$i] = intval($array[$i]);
98
+ }
99
+ }
100
+
101
+ $array = array_unique($array);
102
+ $snippet[$key] = $array;
103
+ return $snippet;
104
+ }
105
+
106
+ public function rc() {
107
+ global $tcm;
108
+ $result = 6-$this->codesCount();
109
+ return $result;
110
+ }
111
+
112
+ //add or update a snippet (html tracking code)
113
+ public function put($id, $snippet) {
114
+ global $tcm;
115
+
116
+ if ($id == '' || intval($id) <= 0) {
117
+ //if is a new code create a new unique id
118
+ $id = $this->getLastId() + 1;
119
+ $snippet['id'] = $id;
120
+ }
121
+ $snippet=$this->sanitize($id, $snippet);
122
+ $tcm->Options->setSnippet($id, $snippet);
123
+
124
+ $keys = $this->keys();
125
+ if (is_array($keys) && !in_array($id, $keys)) {
126
+ $keys[] = $id;
127
+ $this->keys($keys);
128
+ }
129
+ return $snippet;
130
+ }
131
+
132
+ //remove the id snippet
133
+ public function remove($id) {
134
+ global $tcm;
135
+ $tcm->Options->removeSnippet($id);
136
+ $keys=$this->keys();
137
+ $result = FALSE;
138
+ if (is_array($keys) && in_array($id, $keys)) {
139
+ $keys = array_diff($keys, array($id));
140
+ $this->keys($keys);
141
+ $result = TRUE;
142
+ }
143
+ return $result;
144
+ }
145
+
146
+ //verify if match with this snippet
147
+ private function matchSnippet($postId, $postType, $categoriesIds, $tagsIds, $prefix, $snippet) {
148
+ global $tcm;
149
+
150
+ $include=FALSE;
151
+ $postId=intval($postId);
152
+ if($postId>0) {
153
+ $what=$prefix.'PostsOfType_'.$postType;
154
+ if(!$include && $snippet[$what.'_Active'] && $tcm->Utils->inArray($postId, $snippet[$what])) {
155
+ $tcm->Logger->debug('MATCH=%s SNIPPET=%s[%s] DUE TO POST=%s OF TYPE=%s IN [%s]'
156
+ , $prefix, $snippet['ID'], $snippet['name'], $postId, $postType, $snippet[$what]);
157
+ $include=TRUE;
158
+ }
159
+ }
160
+
161
+ return $include;
162
+ }
163
+
164
+ public function writeCodes($position) {
165
+ global $tcm;
166
+
167
+ $text='';
168
+ switch ($position) {
169
+ case TCM_POSITION_HEAD:
170
+ $text='HEAD';
171
+ break;
172
+ case TCM_POSITION_BODY:
173
+ $text='BODY';
174
+ break;
175
+ case TCM_POSITION_FOOTER:
176
+ $text='FOOTER';
177
+ break;
178
+ }
179
+
180
+ $post=$tcm->Options->getPostShown();
181
+ $args=array('field'=>'code');
182
+ $codes=$tcm->Manager->getCodes($position, $post, $args);
183
+ if(is_array($codes) && count($codes)>0) {
184
+ echo "\n<!--BEGIN: TRACKING CODE MANAGER BY INTELLYWP.COM IN $text//-->";
185
+ foreach($codes as $v) {
186
+ echo "\n$v";
187
+ }
188
+ echo "\n<!--END: TRACKING CODE MANAGER BY INTELLYWP.COM IN $text//-->";
189
+ }
190
+ }
191
+
192
+ //from a post retrieve the html code that is needed to insert into the page code
193
+ public function getCodes($position, $post, $args=array()) {
194
+ global $tcm;
195
+
196
+ $defaults=array('metabox'=>FALSE, 'field'=>'code');
197
+ $args=wp_parse_args($args, $defaults);
198
+
199
+ $postId=0;
200
+ $postType='page';
201
+ $tagsIds=array();
202
+ $categoriesIds=array();
203
+ if($post) {
204
+ $postId = $post->ID;
205
+ $postType = $post->post_type;
206
+ }
207
+
208
+ $tcm->Options->clearSnippetsWritten();
209
+ $keys=$this->keys();
210
+ foreach ($keys as $id) {
211
+ $v=$this->get($id);
212
+ if(!$v || ($position>-1 && $v['position']!=$position) || $v['code']=='' || (!$args['metabox'] && !$v['active'])) {
213
+ continue;
214
+ }
215
+ if($tcm->Options->hasSnippetWritten($v)) {
216
+ $tcm->Logger->debug('SKIPPED SNIPPET=%s[%s] DUE TO ALREADY WRITTEN', $v['ID'], $v['name']);
217
+ continue;
218
+ }
219
+
220
+ $match=FALSE;
221
+ if(!$match && $v['includeEverywhereActive']) {
222
+ $tcm->Logger->debug('INCLUDED SNIPPET=%s[%s] DUE TO EVERYWHERE', $v['ID'], $v['name']);
223
+ $match=TRUE;
224
+ }
225
+ if(!$match && $postId>0 && $this->matchSnippet($postId, $postType, $categoriesIds, $tagsIds, 'include', $v)) {
226
+ $match=TRUE;
227
+ }
228
+
229
+ if($match && $postId>0) {
230
+ if($this->matchSnippet($postId, $postType, $categoriesIds, $tagsIds, 'except', $v)) {
231
+ $tcm->Logger->debug('FOUND AT LEAST ON EXCEPT TO EXCLUDE SNIPPET=%s [%s]', $v['id'], $v['name']);
232
+ $match=FALSE;
233
+ }
234
+ }
235
+
236
+ if ($match) {
237
+ $tcm->Options->pushSnippetWritten($v);
238
+ }
239
+ }
240
+
241
+ //obtain result as snippets or array of one field (tipically "id")
242
+ $result=$tcm->Options->getSnippetsWritten();
243
+ if ($args['field']!='all') {
244
+ $array=array();
245
+ foreach($result as $k=>$v) {
246
+ $k=$args['field'];
247
+ if(isset($v[$k])) {
248
+ $array[]=$v[$k];
249
+ } else {
250
+ $tcm->Logger->error('SNIPPET=%s [%s] WITHOUT FIELD=%s', $v['id'], $v['name'], $k);
251
+ }
252
+ }
253
+ $result=$array;
254
+ }
255
+ return $result;
256
+ }
257
+
258
+ //ottiene o salva tutte le chiavi dei tracking code utilizzati ordinati per id
259
+ public function keys($keys=NULL) {
260
+ global $tcm;
261
+
262
+ if (is_array($keys)) {
263
+ $tcm->Options->setSnippetList($keys);
264
+ $result=$keys;
265
+ } else {
266
+ $result=$tcm->Options->getSnippetList();
267
+ }
268
+
269
+ if (!is_array($result)) {
270
+ $result = array();
271
+ } else {
272
+ sort($result);
273
+ }
274
+ return $result;
275
+ }
276
+
277
+ //ottiene il conteggio attuale dei tracking code
278
+ public function count() {
279
+ $result = count($this->keys());
280
+ return $result;
281
+ }
282
+ public function codesCount() {
283
+ $result=0;
284
+ $ids=$this->keys();
285
+ foreach($ids as $id) {
286
+ $snippet=$this->get($id);
287
+ if($snippet) {
288
+ if($snippet['codesCount']>0) {
289
+ $result+=intval($snippet['codesCount']);
290
+ } else {
291
+ $result+=1;
292
+ }
293
+ }
294
+ }
295
+ return $result;
296
+ }
297
+ public function getLastId() {
298
+ $result = 0;
299
+ $list = $this->keys();
300
+ foreach ($list as $v) {
301
+ $v = intval($v);
302
+ if ($v > $result) {
303
+ $result = $v;
304
+ }
305
+ }
306
+ return $result;
307
+ }
308
+
309
+ //ottiene tutti i tracking code ordinati per nome
310
+ public function values() {
311
+ $keys = $this->keys();
312
+ $result = array();
313
+ foreach ($keys as $k) {
314
+ $v = $this->get($k);
315
+ $result[strtoupper($v['name'])] = $v;
316
+ }
317
+ ksort($result);
318
+ return $result;
319
+ }
320
+ }
includes/class-TCM-options.php ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ //TrackingLastSendPro
106
+ public function getTrackingLastSend() {
107
+ return $this->getOption('TrackingLastSend', 0);
108
+ }
109
+ public function setTrackingLastSend($value) {
110
+ $this->setOption('TrackingLastSend', $value);
111
+ }
112
+
113
+ //LoggerEnable
114
+ public function isLoggerEnable() {
115
+ return ($this->getOption('LoggerEnable', FALSE) || (defined('TCM_LOGGER') && TCM_LOGGER));
116
+ }
117
+ public function setLoggerEnable($value) {
118
+ $this->setOption('LoggerEnable', $value);
119
+ }
120
+
121
+ //Snippet
122
+ public function getSnippet($id) {
123
+ return $this->getOption('Snippet_'.$id, NULL);
124
+ }
125
+ public function setSnippet($id, $value) {
126
+ $this->setOption('Snippet_'.$id, $value);
127
+ }
128
+ public function removeSnippet($id) {
129
+ $this->removeOption('Snippet_'.$id);
130
+ }
131
+ //SnippetList
132
+ public function getSnippetList() {
133
+ return $this->getOption('SnippetList', array());
134
+ }
135
+ public function setSnippetList($value) {
136
+ $this->setOption('SnippetList', $value);
137
+ }
138
+ public function removeSnippetList() {
139
+ $this->removeOption('SnippetList');
140
+ }
141
+
142
+ public function hasSnippetWritten($snippet) {
143
+ //check also the md5 of code so if the user create 2 different snippets with
144
+ //the same tracking code we will not insert into 2 times inside the html
145
+ $id=$snippet['id'];
146
+ $md5=md5($snippet['code']);
147
+
148
+ $listIds=$this->getRequest('SnippetsWrittenIds', array());
149
+ $listMd5=$this->getRequest('SnippetsWrittenMd5', array());
150
+
151
+ $result=(in_array($id, $listIds) || in_array($md5, $listMd5));
152
+ return $result;
153
+ }
154
+ public function pushSnippetWritten($snippet) {
155
+ $md5=md5($snippet['code']);
156
+ $id=$snippet['id'];
157
+ $listIds=$this->getRequest('SnippetsWrittenIds', array());
158
+ $listMd5=$this->getRequest('SnippetsWrittenMd5', array());
159
+
160
+ $listIds[$id]=$snippet;
161
+ $listMd5[$md5]=$id;
162
+ $this->setRequest('SnippetsWrittenIds', $listIds);
163
+ $this->setRequest('SnippetsWrittenMd5', $listMd5);
164
+ }
165
+ public function getSnippetsWritten() {
166
+ return $this->getRequest('SnippetsWrittenIds', array());
167
+ }
168
+ public function clearSnippetsWritten() {
169
+ $this->setRequest('SnippetsWrittenIds', array());
170
+ $this->setRequest('SnippetsWrittenMd5', array());
171
+ }
172
+
173
+ //PostShown
174
+ public function getPostShown() {
175
+ return $this->getRequest('PostShown');
176
+ }
177
+ public function setPostShown($post) {
178
+ $this->setRequest('PostShown', $post);
179
+ }
180
+ //Cache
181
+ public function getCache($name, $id) {
182
+ return $this->getRequest('Cache_'.$name.'_'.$id);
183
+ }
184
+ public function setCache($name, $id, $value) {
185
+ $this->setRequest('Cache_'.$name.'_'.$id, $value);
186
+ }
187
+
188
+ //ErrorMessages
189
+ public function hasErrorMessages() {
190
+ $result=$this->getRequest('ErrorMessages', NULL);
191
+ return (is_array($result) && count($result)>0);
192
+ }
193
+ public function pushErrorMessage($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
194
+ global $tcm;
195
+ $array=$this->getRequest('ErrorMessages', array());
196
+ $array[]=$tcm->Lang->L($message, $v1, $v2, $v3, $v4, $v5);
197
+ $this->setRequest('ErrorMessages', $array);
198
+ }
199
+ public function writeErrorMessages($clean=TRUE) {
200
+ global $tcm;
201
+ $array=$this->getRequest('ErrorMessages', array());
202
+ if(is_array($array) && count($array)>0) { ?>
203
+ <div class="message error"><?php echo wpautop(implode("\n", $array)); ?></div>
204
+ <?php }
205
+ if($clean) {
206
+ $this->removeRequest('ErrorMessages');
207
+ }
208
+ }
209
+ //SuccessMessages
210
+ public function hasSuccessMessages() {
211
+ $result=$this->getRequest('SuccessMessages', NULL);
212
+ return (is_array($result) && count($result)>0);
213
+ }
214
+ public function pushSuccessMessage($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
215
+ global $tcm;
216
+ $array=$this->getRequest('SuccessMessages', array());
217
+ $array[]=$tcm->Lang->L($message, $v1, $v2, $v3, $v4, $v5);
218
+ $this->setRequest('SuccessMessages', $array);
219
+ }
220
+ public function writeSuccessMessages($clean=TRUE) {
221
+ $array=$this->getRequest('SuccessMessages', array());
222
+ if(is_array($array) && count($array)>0) { ?>
223
+ <div class="message updated"><?php echo wpautop(implode("\n", $array)); ?></div>
224
+ <?php }
225
+ if($clean) {
226
+ $this->removeRequest('SuccessMessages');
227
+ }
228
+ }
229
+ public function writeMessages($clean=TRUE) {
230
+ $this->writeErrorMessages($clean);
231
+ $this->writeSuccessMessages($clean);
232
+ }
233
+ public function pushMessage($success, $message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
234
+ if($success) {
235
+ $this->pushSuccessMessage($message.'Success', $v1, $v2, $v3, $v4, $v5);
236
+ } else {
237
+ $this->pushErrorMessage($message.'Error', $v1, $v2, $v3, $v4, $v5);
238
+ }
239
+ }
240
+
241
+ public function getFeedbackEmail() {
242
+ return $this->getOption('FeedbackEmail', get_bloginfo('admin_email'));
243
+ }
244
+ public function setFeedbackEmail($value) {
245
+ $this->setOption('FeedbackEmail', $value);
246
+ }
247
+
248
+ //MetaboxPostTypes
249
+ public function getMetaboxPostTypes($create=TRUE) {
250
+ global $tcm;
251
+ $result=$this->getOption('MetaboxPostTypes', array());
252
+ if($create) {
253
+ $types=$tcm->Utils->query(TCM_QUERY_POST_TYPES);
254
+ foreach($types as $v) {
255
+ $v=$v['id'];
256
+ if(!isset($result[$v])) {
257
+ $result[$v]=1;
258
+ }
259
+ }
260
+ }
261
+ return $result;
262
+ }
263
+ public function setMetaboxPostTypes($values) {
264
+ $this->setOption('MetaboxPostTypes', $values);
265
+ }
266
+ }
includes/class-TCM-tracking.php ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Exit if accessed directly
4
+ if (!defined('ABSPATH')) exit;
5
+
6
+ /**
7
+ * Usage tracking
8
+ *
9
+ * @access public
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
+
25
+ private function getThemeData() {
26
+ $theme_data = wp_get_theme();
27
+ $theme = array(
28
+ 'name' => $theme_data->display( 'Name', false, false ),
29
+ 'theme_uri' => $theme_data->display( 'ThemeURI', false, false ),
30
+ 'version' => $theme_data->display( 'Version', false, false ),
31
+ 'author' => $theme_data->display( 'Author', false, false ),
32
+ 'author_uri' => $theme_data->display( 'AuthorURI', false, false ),
33
+ );
34
+ $theme_template = $theme_data->get_template();
35
+ if ( $theme_template !== '' && $theme_data->parent() ) {
36
+ $theme['template'] = array(
37
+ 'version' => $theme_data->parent()->display( 'Version', false, false ),
38
+ 'name' => $theme_data->parent()->display( 'Name', false, false ),
39
+ 'theme_uri' => $theme_data->parent()->display( 'ThemeURI', false, false ),
40
+ 'author' => $theme_data->parent()->display( 'Author', false, false ),
41
+ 'author_uri' => $theme_data->parent()->display( 'AuthorURI', false, false ),
42
+ );
43
+ }
44
+ else {
45
+ $theme['template'] = '';
46
+ }
47
+ unset( $theme_template );
48
+ return $theme;
49
+ }
50
+ private function getPluginData() {
51
+ //retrieve plugins (active/inactive) list
52
+ if(!function_exists('get_plugins')) {
53
+ include ABSPATH . '/wp-admin/includes/plugin.php';
54
+ }
55
+
56
+ $plugins=array();
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 );
64
+
65
+ $slug= str_replace( '/' . basename( $plugin_path ), '', $plugin_path );
66
+ $plugins[ $slug ] = array(
67
+ 'version' => $plugin_info['Version'],
68
+ 'name' => $plugin_info['Name'],
69
+ 'plugin_uri' => $plugin_info['PluginURI'],
70
+ 'author' => $plugin_info['AuthorName'],
71
+ 'author_uri' => $plugin_info['AuthorURI'],
72
+ );
73
+ }
74
+ unset( $active_plugins, $plugin_path );
75
+ return $plugins;
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();
83
+ $result['wp_version']=get_bloginfo('version');
84
+ $result['wp_language']=get_bloginfo('language');
85
+ $result['wp_wpurl']=get_bloginfo('wpurl');
86
+ $result['wp_admin_email']=get_bloginfo('admin_email');
87
+
88
+ $result['plugins']=$this->getPluginData();
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
+
115
+ $result['iwpm_tracking_enable']=$tcm->Options->isTrackingEnable();
116
+ $result['iwpm_logger_enable']=$tcm->Options->isLoggerEnable();
117
+ $result['iwpm_feedback_email']=$tcm->Options->getFeedbackEmail();
118
+
119
+ //var_dump($result);
120
+ return $result;
121
+ }
122
+
123
+ //send tracking data info to our server
124
+ public function sendTracking($override = FALSE) {
125
+ global $tcm;
126
+
127
+ $result=-1;
128
+ if(!$override && !$tcm->Options->isTrackingEnable())
129
+ return $result;
130
+
131
+ // Send a maximum of once per week
132
+ $last_send=$tcm->Options->getTrackingLastSend();
133
+ if(!$override && $last_send>strtotime('-1 week'))
134
+ return $result;
135
+
136
+ //add_filter('https_local_ssl_verify', '__return_false');
137
+ //add_filter('https_ssl_verify', '__return_false');
138
+ //add_filter('block_local_requests', '__return_false');
139
+
140
+ $data=$tcm->Utils->remotePost('usage', $this->getData());
141
+ if($data) {
142
+ $result=intval($data['id']);
143
+ $tcm->Options->setTrackingLastSend(time());
144
+ }
145
+ return $result;
146
+ }
147
+
148
+ public function enableTracking() {
149
+ global $tcm;
150
+
151
+ $tcm->Options->setTrackingEnable(TRUE);
152
+ $tcm->Options->setTrackingNotice(FALSE);
153
+ $this->sendTracking(TRUE);
154
+ }
155
+ public function disableTracking() {
156
+ global $tcm;
157
+
158
+ $tcm->Options->setTrackingEnable(FALSE);
159
+ $tcm->Options->setTrackingNotice(FALSE);
160
+ $this->sendTracking(TRUE);
161
+ }
162
+
163
+ public function admin_notice() {
164
+ global $tcm;
165
+
166
+ if(!$tcm->Options->isTrackingNotice() || $tcm->Options->isTrackingEnable() || !current_user_can('manage_options'))
167
+ return;
168
+
169
+ if(FALSE && (
170
+ stristr(network_site_url('/'), 'dev' ) !== false ||
171
+ stristr(network_site_url('/'), 'localhost') !== false ||
172
+ stristr(network_site_url('/'), ':8888' ) !== false // This is common with MAMP on OS X
173
+ )) {
174
+ $tcm->Options->setTrackingNotice(TRUE);
175
+ } else {
176
+ $yes_url=add_query_arg('tcm_action', 'manager_trackingOn');
177
+ $no_url=add_query_arg('tcm_action', 'manager_trackingOff');
178
+
179
+ ?>
180
+ <div class="updated">
181
+ <p>
182
+ <?php $tcm->Lang->P('Allow IntellyWP to track plugin usage?');?>
183
+ &nbsp;<a href="<?php echo esc_url($yes_url)?>" class="button-primary"><?php $tcm->Lang->P('Oh yes :)')?></a>
184
+ &nbsp;<a href="<?php echo esc_url($no_url)?>" class="button-secondary"><?php $tcm->Lang->P('Refuse!')?></a>
185
+ </p>
186
+ </div>
187
+ <?php }
188
+ }
189
+ }
includes/class-TCM-utils.php ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
71
+ //per ottenere un campo dal $_GET oppure dal $_POST
72
+ function qs($name, $default = '') {
73
+ $result = $default;
74
+ if (isset($_GET[$name])) {
75
+ $result = $_GET[$name];
76
+ } elseif (isset($_POST[$name])) {
77
+ $result = $_POST[$name];
78
+ }
79
+
80
+ if (is_string($result)) {
81
+ $result = urldecode($result);
82
+ $result = trim($result);
83
+ }
84
+
85
+ return $result;
86
+ }
87
+
88
+ function query($query, $args = NULL) {
89
+ global $tcm;
90
+
91
+ $defaults = array('post_type' => '', 'all' => FALSE);
92
+ $args = wp_parse_args($args, $defaults);
93
+
94
+ $result = $tcm->Options->getCache('Query', $query . '_' . $args['post_type']);
95
+ if (!is_array($result) || count($result) == 0) {
96
+ $q = NULL;
97
+ $id = 'ID';
98
+ $name = 'post_title';
99
+ switch ($query) {
100
+ case TCM_QUERY_POSTS_OF_TYPE:
101
+ $options = array('posts_per_page' => -1, 'post_type' => $args['post_type']);
102
+ $q = get_posts($options);
103
+ break;
104
+ }
105
+
106
+ $result = array();
107
+ if ($q) {
108
+ foreach ($q as $v) {
109
+ $result[] = array('id' => $v->$id, 'name' => $v->$name);
110
+ }
111
+ } elseif ($query == TCM_QUERY_POST_TYPES) {
112
+ $q=array('post', 'page');
113
+ sort($q);
114
+ foreach ($q as $v) {
115
+ $result[] = array('id' => $v, 'name' => $v);
116
+ }
117
+ }
118
+
119
+ $tcm->Options->setCache('Query', $query . '_' . $args['post_type'], $result);
120
+ }
121
+
122
+ if ($args['all']) {
123
+ $first = array();
124
+ $first[] = array('id' => -1, 'name' => '[' . $tcm->Lang->L('All') . ']');
125
+ $result = array_merge($first, $result);
126
+ }
127
+
128
+ return $result;
129
+ }
130
+
131
+ //send remote request to our server to store tracking and feedback
132
+ function remotePost($action, $data = '') {
133
+ global $tcm;
134
+
135
+ $data['secret'] = 'WYSIWYG';
136
+ $response = wp_remote_post(TCM_INTELLYWP_RECEIVER . '?iwpm_action=' . $action, array(
137
+ 'method' => 'POST'
138
+ , 'timeout' => 20
139
+ , 'redirection' => 5
140
+ , 'httpversion' => '1.1'
141
+ , 'blocking' => TRUE
142
+ , 'body' => $data
143
+ , 'user-agent' => 'TCM/' . TCM_PLUGIN_VERSION . '; ' . get_bloginfo('url')
144
+ ));
145
+ $data = json_decode(wp_remote_retrieve_body($response), TRUE);
146
+ if (is_wp_error($response) || wp_remote_retrieve_response_code($response) != 200
147
+ || !isset($data['success']) || !$data['success']
148
+ ) {
149
+ $tcm->Logger->error('ERRORS SENDING REMOTE-POST ACTION=%s DUE TO REASON=%s', $action, $response);
150
+ $data = FALSE;
151
+ } else {
152
+ $tcm->Logger->debug('SUCCESSFULLY SENT REMOTE-POST ACTION=%s RESPONSE=%s', $action, $data);
153
+ }
154
+ return $data;
155
+ }
156
+
157
+ //wp_parse_args with null correction
158
+ function parseArgs($args, $defaults) {
159
+ if (is_null($args) || !is_array($args)) {
160
+ $args = array();
161
+ }
162
+ foreach ($args as $k => $v) {
163
+ if (is_null($args[$k])) {
164
+ //so can take the default value
165
+ unset($args[$k]);
166
+ } elseif (is_string($args[$k]) && $args[$k] == '' && isset($defaults[$k]) && is_array($defaults[$k])) {
167
+ //a very strange case, i have a blank string for rappresenting an empty array
168
+ unset($args[$k]);
169
+ }
170
+ }
171
+ $result = wp_parse_args($args, $defaults);
172
+ return $result;
173
+ }
174
+
175
+ function redirect($location) {
176
+ //seems that if you have installed xdebug (or some version of it) doesnt work so js added
177
+ wp_redirect($location);
178
+ ?>
179
+ <script> window.location.replace('<?php echo $location?>'); </script>
180
+ <?php }
181
+ }
includes/core.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //per agganciarsi ogni volta che viene scritto un contenuto
3
+ add_filter('wp_head', 'tcm_head');
4
+ function tcm_head(){
5
+ global $post, $tcm;
6
+
7
+ $tcm->Options->setPostShown(NULL);
8
+ if(is_page($post->ID) || is_single($post->ID)) {
9
+ $tcm->Options->setPostShown($post);
10
+ $tcm->Logger->info('POST ID=%s IS SHOWN', $post->ID);
11
+ }
12
+
13
+ //future development
14
+ //is_archive();
15
+ //is_post_type_archive();
16
+ //is_post_type_hierarchical();
17
+ //is_attachment();
18
+ $tcm->Manager->writeCodes(TCM_POSITION_HEAD);
19
+ }
20
+ add_action('wp_footer', 'tcm_footer');
21
+ function tcm_footer() {
22
+ global $tcm;
23
+ //there isn't a hook when <BODY> starts
24
+ $tcm->Manager->writeCodes(TCM_POSITION_BODY);
25
+ $tcm->Manager->writeCodes(TCM_POSITION_FOOTER);
26
+ }
includes/install.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ function tcm_install($networkwide=NULL) {
4
+ global $wpdb;
5
+ }
6
+
7
+ register_activation_hook(TCM_PLUGIN_FILE, 'tcm_install');
8
+
9
+
10
+
11
+
12
+
includes/uninstall.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ function tcm_uninstall($networkwide=NULL) {
4
+ global $wpdb;
5
+
6
+ }
7
+
8
+ register_uninstall_hook(TCM_PLUGIN_FILE, 'tcm_uninstall');
9
+ ?>
languages/TCM.txt ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #en_US
2
+ PluginLimit.Line1=In this FREE version you can insert up to N.{0} different Tracking Code (remaining N.{1})
3
+ PluginLimit.Line2=If you need more Tracking Code or more features please buy our PREMIUM version <a href="{0}" target="_blank"><b>HERE</b></a>
4
+ Editor.Add=Tracking Code "#{0} ({1})" successfully stored.
5
+ Button.Add=Add a new Tracking Code
6
+ Button.BuyPRO=Buy PREMIUM
7
+
8
+ Feedback.email=Contact email
9
+ Feedback.email.check=Please specify a valid email
10
+ Feedback.body=Feedback
11
+ Feedback.body.check=Please specify your feedback
12
+ Feedback.track=Send also track information (this can be very useful for us to solve your issue)
13
+ FeedbackSuccess=Feedback successfully sent. We will reply you ASAP.
14
+ FeedbackError=Errors sending feedback. Please email us at aleste@intellywp.com
15
+
16
+ AboutNotice=Thank you for trying our amazing plugin. Now you are able to quickly track what you need. Feel free to contact us using our feedback form or our email <a href="mailto:aleste@intellywp.com">aleste@intellywp.com</a>
17
+ AboutTitle=We are crazy! But...
18
+ ManagerTitle=Tracking Code Manager FREE
19
+ ManagerSubtitle=<b>WARNING</b> This does not filter your HTML code for errors or for malicious scripts. Use it at your own risk.
20
+ SettingsTitle=Plugin settings
21
+ FeedbackHeader=Like this plugin? Send us a feedback
22
+ AboutText1=We are Stefano and Alessio, two guys in love with Wordpress, coding and marketing! Our company IntellyWP is an idea to bring Intelly ideas to your Intelly site ;)
23
+ AboutText2=Feel free to reach us by the feedback form below.
24
+
25
+ CodeDeleteNotice=Tracking code "#{0} ({1})" successfully deleted
26
+ CodeUpdateNotice=Tracking code "#{0} ({1})" successfully updated
27
+ CodeAddNotice=Tracking code "#{0} ({1})" successfully added
28
+
29
+ FreeLicenseReached=You have reached the FREE version limit. Please buy the PREMIUM version or delete unused tracking code and create new ones.
30
+ EditTitle=Edit tracking code
31
+ EditSubtitle=Edit the information that you need and click "Save"
32
+ AddTitle=New tracking code
33
+ AddSubtitle=Fill in the information and click "Save"
34
+ EnableAllowTrackingNotice1=Currently we receive plugin usage information. It allows us to have a BETTER development so many many thanks from the development team.
35
+ EnableAllowTrackingNotice2=If you want to stop tracking please click <a href="{0}">HERE :(</a>
36
+ DisableAllowTrackingNotice1=Ooops... Seems that you are not allowing us to receive plugin usage information. It allows us to have a BETTER development without collecting any sensitive-data.
37
+ DisableAllowTrackingNotice2=Please allow us to receive this information click <a href="{0}">HERE :)</a>
38
+
39
+ Editor.active=Active?
40
+ Editor.name=Name
41
+ Editor.code=Paste your Tracking Code here
42
+ Editor.position.0=Before &lt;/HEAD&gt;
43
+ Editor.position.1=After &lt;BODY&gt;
44
+ Editor.position.2=Before &lt;/BODY&gt;
45
+ Editor.position=Position inside the code
46
+ Editor.includeEverywhereActive=Include in the whole website (pages, posts and archives)
47
+ Editor.includeCategoriesActive=Include in posts with specific categories
48
+ Editor.includeTagsActive=Include in posts with specific tags
49
+ Editor.includePostsOfTypeActive=Include in "<b>{0}</b>"
50
+ Editor.exceptCategoriesActive=Except in posts with specific categories
51
+ Editor.exceptTagsActive=Except in posts with specific tags
52
+ Editor.exceptPostsOfTypeActive=Except in "<b>{0}</b>"
53
+ Editor.includeLastPostsActive=Include in lastest posts (specify the number posts)
54
+
55
+ DeactivateSuccess=License key "{0}" successfully deactivated
56
+ DeactivateError=Errors deactivating key. Network problem??
57
+ ActivateSuccess1=License key "{0}" successfully activated
58
+ ActivateSuccess2=CONGRATS...YOU ARE NOW A PREMIUM MEMBER! :)
59
+ ActivateError=Errors activating key. Network problem or wrong password
60
+
61
+ LicenseSection=License information
62
+ LicenseSectionSubtitle=You can obtain your PREMIUM license key (that will unlock all the amazing features) click <a href="{0}" target="_new">HERE</a>
63
+ MetaboxSection=Metabox information
64
+ MetaboxSectionSubtitle=Check in which post type do you want integrate our metabox widget
65
+ License.metabox=In "<b>{0}</b>"
66
+ License.key=Insert the activation key received by email
67
+ EmptyTrackingList=Your tracking code list is empty, please <a href="{0}">CLICK HERE</a> to create new ones.
68
+
69
+ Notice.ProHeader1=Do you like this plugin?
70
+ Notice.ProHeader2=Using the <b>PREMIUM</b> version you can also include/except tracking code:
71
+ Notice.ProFeature1=In your custom post type (p.e. <b>{0}</b>)
72
+ Notice.ProFeature2=In the lastest post
73
+ Notice.ProFeature3=In specific categories
74
+ Notice.ProFeature4=In specific tags
readme.txt ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Tracking Code Manager ===
2
+ Contributors: IntellyWP
3
+ Donate link: http://intellywp.com/tracking-code-manager/
4
+ Tags: remarketing,retargeting,tracking cookies,ppc management,tracking code,facebook retargeting,eye tracking software,adwords remarketing,conversion tracking,facebook conversion pixel,facebook pixel conversion,conversion pixel,conversion tracking pixel,conversion tracking adwords,tracking codes,trackingcode,analytics conversion tracking,track conversion,conversion code,conversion adwords,adwords conversion tracking code,tracking pixel code,pixel tracking code,tracking script,tracking code analytics,conversion tracking software,ppc tracking,conversion tracking analytics,track conversions,conversion pixel tracking,html tracking,adword conversion tracking,conversion tracking tool,tracking conversions,url tracking code,html tracking code,google analytics web tracking code,pay per click tracking,conversion tracking script,snipplets
5
+ Requires at least: 2.7
6
+ Tested up to: 4.1.1
7
+
8
+ A plugin to manage ALL your tracking code and conversion pixels, simply.
9
+ Compatible with Facebook Ads, Google Adwords and ALL kind of Saas tool.
10
+
11
+ == Description ==
12
+
13
+ **Tracking Code manageris a plugin that give you the ability to manage ALL your tracking code and scripts in one single page.**
14
+
15
+ It doesn’t matter the place where you want to put your code, because with Tracking Code Manager you can put it wherever you want, with no restrictions.
16
+
17
+ Let’s say you are using on your website Google Analytics, Facebook Custom Audiences, Facebook Retargeting, Google Remarketing, Zendesk, a Live Chat tool, eye tracking analytics, popups, affiliate tracking pixels and so on...
18
+
19
+ For every single service you use, you’ll have to put a script or a tracking pixel in the &lt;head&gt; or &lt;body&gt; tag of your WordPress site OR in some of its pages.
20
+
21
+ Tracking Code Manager plugin allows you to gather EVERY code and snippet displaying them exactly where you want, whether in the whole site or in specific pages and posts.
22
+
23
+ = THE REAL PROBLEM =
24
+
25
+ We are living in the Saas era, where online services manage all kind of software, analysis and advanced tools. Since every one of them needs a script or a tracking code, why don’t we take it easy with the fast Tracking Code Manager plugin?
26
+
27
+ = FORGET THE UPDATING PROBLEM =
28
+
29
+ Putting the tracking code directly in the theme files, you risk to lose important trackings or external service integrations when it will be updated.
30
+
31
+ With Tracking Code Manager you can forget about this problem also if you will change your theme in the future.
32
+
33
+ [youtube https://www.youtube.com/watch?v=shJG7Vf1nMg]
34
+
35
+ = PREMIUM VERSION =
36
+
37
+ If you need more advanced feature you can also try our PREMIUM version available in the link [http://intellywp.com/tracking-code-manager/](http://intellywp.com/tracking-code-manager/). This is our official webpage, you will see the plugin in action, with the possibility to buy PREMIUM version and have full support.
38
+
39
+ == Installation ==
40
+
41
+ 1. Download
42
+ 2. Upload to your /wp-contents/plugins/ directory.
43
+ 3. Activate the plugin through the 'Plugins' menu in WordPress.
44
+ 4. Put your tracking code, script or iframe in the plugin by going to the Settings =&gt; Tracking Code Manager menu
45
+
46
+ You can also click on this link [http://intellywp.com/tracking-code-manager/](http://intellywp.com/tracking-code-manager/) to see a full explanation. This is our official webpage, you will see the plugin in action, with the possibility to buy PREMIUM version and have full support.
47
+
48
+ == Frequently Asked Questions ==
49
+
50
+ = Do you have a video that show me the plugin working? =
51
+
52
+ Sure! Click on the link [http://intellywp.com/tracking-code-manager/](http://intellywp.com/tracking-code-manager/) for a full explanation. This is our official webpage, you will see the plugin in action, with the possibility to buy PREMIUM version and have full support.
53
+
54
+ = Will this plugin slow my website? =
55
+
56
+ Absolutely not! Since this plugin is built with lightweight code, you won’t notice any difference in speed.
57
+
58
+ = Can I put a tracking code or a script in ONE (maybe TWO?) specific page? =
59
+
60
+ Of course you can! You can choose to put the code in a single page, in some posts, or in the whole website (more features in pro version).
61
+
62
+ = Can I track conversions? =
63
+
64
+ Yeap! This is one of the main reason to use this plugin! You can track your conversions by putting the conversion pixel or code ONLY inside the thank you page.
65
+
66
+ = Can I manage Facebook Retargeting and Custom Audiences? =
67
+
68
+ Yes! For example you can put Facebook Pixel inside a certain posts of your blog to retarget those users who have already visited that posts on Facebook.
69
+
70
+ = Will this plugin interferes with my Google Analytics plugin? =
71
+
72
+ Nope! We tested the most famous Google Analytics plugins and it will not brake any of them.
73
+
74
+ == Screenshots ==
75
+
76
+ 1. New tracking code scripts
77
+ 2. Include tracking code in specific page
78
+ 3. Choose easly by typing the page title
79
+ 4. Include also [All] posts or pages without selecting all one-by-one
80
+ 5. List your tracking codes defined
81
+ 6. Tracking code manager is also as a metabox in your posts/pages (you can remove by settings)
82
+
83
+ == Changelog ==
84
+
85
+ = 1.4 =
86
+ * 06/04/2015
87
+ * Created the FREE version following Wordpress specs. Branching the PRO version available to buy using website http://www.intellywp.com/tracking-code-manager
88
+
89
+ = 1.3 =
90
+ * 02/04/2015
91
+ * Fixed a bug that caused the hidden of "Save" button when the license if FREE
92
+
93
+ = 1.2 =
94
+ * Introduced new "Except" feature
95
+
96
+ = 1.1 =
97
+ * Introduced new "Custom Post type" feature
98
+
99
+ = 1.0 =
100
+ * First release
screenshot-1.png ADDED
Binary file
screenshot-2.png ADDED
Binary file
screenshot-3.png ADDED
Binary file
screenshot-4.png ADDED
Binary file
screenshot-5.png ADDED
Binary file
screenshot-6.png ADDED
Binary file
tracking-code-manager.php ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Tracking Code Manager
4
+ Plugin URI: http://intellywp.com/tracking-code-manager/
5
+ Description: A plugin to manage ALL your tracking code and conversion pixels, simply. Compatible with Facebook Ads, Google Adwords and ALL kind of Saas tool.
6
+ Author: IntellyWP
7
+ Author URI: http://intellywp.com/
8
+ Email: aleste@intellywp.com
9
+ Version: 1.4
10
+ */
11
+ define('TCM_PLUGIN_FILE',__FILE__);
12
+ define('TCM_PLUGIN_NAME', 'tracking-code-manager');
13
+ define('TCM_PLUGIN_VERSION', '1.4');
14
+ define('TCM_PLUGIN_AUTHOR', 'IntellyWP');
15
+ define('TCM_PLUGIN_ROOT', dirname(__FILE__).'/');
16
+ define('TCM_PLUGIN_IMAGES', plugins_url( 'assets/images/', __FILE__ ));
17
+
18
+ define('TCM_LOGGER', FALSE);
19
+
20
+ define('TCM_QUERY_POSTS_OF_TYPE', 1);
21
+ define('TCM_QUERY_POST_TYPES', 2);
22
+
23
+ define('TCM_INTELLYWP_SITE', 'http://www.intellywp.com/');
24
+ define('TCM_INTELLYWP_RECEIVER', TCM_INTELLYWP_SITE.'wp-content/plugins/intellywp-manager/data.php');
25
+ define('TCM_PAGE_FAQ', TCM_INTELLYWP_SITE.'tracking-code-manager');
26
+ define('TCM_PAGE_PREMIUM', TCM_INTELLYWP_SITE.'tracking-code-manager');
27
+ define('TCM_PAGE_MANAGER', admin_url().'options-general.php?page='.TCM_PLUGIN_NAME);
28
+
29
+ define('TCM_POSITION_HEAD', 0);
30
+ define('TCM_POSITION_BODY', 1);
31
+ define('TCM_POSITION_FOOTER', 2);
32
+
33
+ define('TCM_TAB_EDITOR', 'editor');
34
+ define('TCM_TAB_EDITOR_URI', TCM_PAGE_MANAGER.'&tab='.TCM_TAB_EDITOR);
35
+ define('TCM_TAB_MANAGER', 'manager');
36
+ define('TCM_TAB_MANAGER_URI', TCM_PAGE_MANAGER.'&tab='.TCM_TAB_MANAGER);
37
+ define('TCM_TAB_SETTINGS', 'settings');
38
+ define('TCM_TAB_SETTINGS_URI', TCM_PAGE_MANAGER.'&tab='.TCM_TAB_SETTINGS);
39
+ define('TCM_TAB_ABOUT', 'about');
40
+ define('TCM_TAB_ABOUT_URI', TCM_PAGE_MANAGER.'&tab='.TCM_TAB_ABOUT);
41
+
42
+ include_once(dirname(__FILE__).'/includes/class-TCM-cron.php');
43
+ include_once(dirname(__FILE__).'/includes/class-TCM-tracking.php');
44
+ include_once(dirname(__FILE__).'/includes/class-TCM-logger.php');
45
+ include_once(dirname(__FILE__).'/includes/class-TCM-manager.php');
46
+ include_once(dirname(__FILE__).'/includes/class-TCM-form.php');
47
+ include_once(dirname(__FILE__).'/includes/class-TCM-options.php');
48
+ include_once(dirname(__FILE__).'/includes/class-TCM-check.php');
49
+ include_once(dirname(__FILE__).'/includes/class-TCM-utils.php');
50
+ include_once(dirname(__FILE__).'/includes/class-TCM-language.php');
51
+
52
+ global $tcm;
53
+ $tcm=new TCM_Singleton();
54
+
55
+ include_once(dirname(__FILE__).'/includes/actions.php');
56
+ include_once(dirname(__FILE__).'/includes/core.php');
57
+ include_once(dirname(__FILE__).'/includes/install.php');
58
+ include_once(dirname(__FILE__).'/includes/uninstall.php');
59
+
60
+ include_once(dirname(__FILE__).'/includes/admin/about.php');
61
+ include_once(dirname(__FILE__).'/includes/admin/editor.php');
62
+ include_once(dirname(__FILE__).'/includes/admin/feedback.php');
63
+ include_once(dirname(__FILE__).'/includes/admin/metabox.php');
64
+ include_once(dirname(__FILE__).'/includes/admin/settings.php');
65
+ include_once(dirname(__FILE__).'/includes/admin/manager.php');
66
+
67
+ class TCM_Singleton {
68
+ var $Lang;
69
+ var $Utils;
70
+ var $Form;
71
+ var $Check;
72
+ var $Options;
73
+ var $Logger;
74
+ var $Cron;
75
+ var $Tracking;
76
+ var $Manager;
77
+
78
+ function __construct() {
79
+ $this->Lang=new TCM_Language();
80
+ $this->Lang->load('tcm', TCM_PLUGIN_ROOT.'languages/TCM.txt');
81
+
82
+ $this->Utils=new TCM_Utils();
83
+ $this->Form=new TCM_Form();
84
+ $this->Check=new TCM_Check();
85
+ $this->Options=new TCM_Options();
86
+ $this->Logger=new TCM_Logger();
87
+ $this->Cron=new TCM_Cron();
88
+ $this->Tracking=new TCM_Tracking();
89
+ $this->Manager=new TCM_Manager();
90
+ }
91
+ }
92
+ //from Settings_API_Tabs_Demo_Plugin
93
+ class TCM_Tabs {
94
+ private $tabs = array();
95
+
96
+ function __construct() {
97
+ add_action('admin_menu', array(&$this, 'attachMenu'));
98
+ add_filter('plugin_action_links', array(&$this, 'pluginActions'), 10, 2);
99
+ add_action('admin_enqueue_scripts', array(&$this, 'enqueueScripts'));
100
+ }
101
+
102
+ function attachMenu() {
103
+ global $tcm;
104
+ $name='Tracking Code Manager';
105
+ add_submenu_page('options-general.php'
106
+ , $name, $name
107
+ , 'edit_posts', TCM_PLUGIN_NAME, array(&$this, 'showTabPage'));
108
+ }
109
+ function pluginActions($links, $file) {
110
+ global $tcm;
111
+ if($file==TCM_PLUGIN_NAME.'/'.TCM_PLUGIN_NAME.'.php'){
112
+ $settings = "<a href='".TCM_PAGE_MANAGER."'>" . $tcm->Lang->L('Settings') . '</a> ';
113
+ $premium = "<a href='".TCM_PAGE_PREMIUM."'>" . $tcm->Lang->L('PREMIUM') . '</a> ';
114
+ $links = array_merge(array($settings, $premium), $links);
115
+ }
116
+ return $links;
117
+ }
118
+ function enqueueScripts() {
119
+ wp_enqueue_script('jquery');
120
+ wp_enqueue_script('suggest');
121
+ wp_enqueue_script('jquery-ui-autocomplete');
122
+
123
+ wp_enqueue_style('tcm-css', plugins_url('assets/css/style.css', __FILE__ ));
124
+ wp_enqueue_style('tcm-select2-css', plugins_url('assets/deps/select2-3.5.2/select2.css', __FILE__ ));
125
+ //wp_enqueue_style('tcm-select2-css2', plugins_url('deps/select2/css/select2.custom.css', __FILE__ ));
126
+ wp_enqueue_script('tcm-select2-js', plugins_url('assets/deps/select2-3.5.2/select2.min.js', __FILE__ ));
127
+
128
+ wp_register_script('tcm-autocomplete', plugins_url('assets/js/tcm-autocomplete.js', __FILE__ ), array('jquery', 'jquery-ui-autocomplete'), '1.0', FALSE);
129
+ wp_localize_script('tcm-autocomplete', 'TCMAutocomplete', array('url' => admin_url('admin-ajax.php')
130
+ ));
131
+ wp_enqueue_script('tcm-autocomplete');
132
+ }
133
+
134
+ function showTabPage() {
135
+ global $tcm;
136
+
137
+ $id=intval($tcm->Utils->qs('id', 0));
138
+ $tab=$tcm->Utils->qs('tab', TCM_TAB_MANAGER);
139
+
140
+ if($id>0 || $tcm->Manager->rc()>0) {
141
+ $this->tabs[TCM_TAB_EDITOR]=$tcm->Lang->L($id>0 ? 'Edit' : 'New');
142
+ } elseif($tab==TCM_TAB_EDITOR) {
143
+ $tab=TCM_TAB_MANAGER;
144
+ }
145
+ $this->tabs[TCM_TAB_MANAGER]=$tcm->Lang->L('Manager');
146
+ $this->tabs[TCM_TAB_SETTINGS]=$tcm->Lang->L('Settings');
147
+ $this->tabs[TCM_TAB_ABOUT]=$tcm->Lang->L('About');
148
+
149
+ ?>
150
+ <div class="wrap" style="margin:5px;">
151
+ <?php
152
+ $this->showTabs();
153
+ $header='';
154
+ switch ($tab) {
155
+ case TCM_TAB_EDITOR:
156
+ $header=($id>0 ? 'Edit' : 'Add');
157
+ break;
158
+ case TCM_TAB_MANAGER:
159
+ $header='Manager';
160
+ break;
161
+ case TCM_TAB_SETTINGS:
162
+ $header='Settings';
163
+ break;
164
+ case TCM_TAB_ABOUT:
165
+ $header='About';
166
+ break;
167
+ }
168
+
169
+ if($tcm->Lang->H($header.'Title')) { ?>
170
+ <h2><?php $tcm->Lang->P($header . 'Title') ?></h2>
171
+ <?php if ($tcm->Lang->H($header . 'Subtitle')) { ?>
172
+ <div><?php $tcm->Lang->P($header . 'Subtitle') ?></div>
173
+ <?php } ?>
174
+ <br/>
175
+ <?php }
176
+
177
+ switch ($tab) {
178
+ case TCM_TAB_EDITOR:
179
+ tcm_ui_editor();
180
+ break;
181
+ case TCM_TAB_MANAGER:
182
+ tcm_ui_manager();
183
+ if($tcm->Manager->count()>0) {
184
+ tcm_ui_feedback();
185
+ }
186
+ break;
187
+ case TCM_TAB_SETTINGS:
188
+ tcm_ui_settings();
189
+ break;
190
+ case TCM_TAB_ABOUT:
191
+ tcm_ui_about();
192
+ tcm_ui_feedback();
193
+ break;
194
+ } ?>
195
+ </div>
196
+ <?php }
197
+
198
+ function showTabs() {
199
+ global $tcm;
200
+ $tab=$tcm->Check->of('tab', TCM_TAB_MANAGER);
201
+
202
+ echo '<h2 class="nav-tab-wrapper">';
203
+ foreach ($this->tabs as $k=>$v) {
204
+ $active = ($tab==$k ? 'nav-tab-active' : '');
205
+ echo '<a class="nav-tab '.$active.'" href="?page='.TCM_PLUGIN_NAME.'&tab='.$k.'">'.$v.'</a>';
206
+ }
207
+ echo '</h2>';
208
+ }
209
+ };
210
+
211
+ $tcmTabs=new TCM_Tabs();