Inline Related Posts - Version 2.2.4

Version Description

Release Date - 2019-05-18

  • Tested with WP 5.2 Plugin updated and supported.
  • [Improvement] Prevent the related posts inside specific divs
Download this release

Release Info

Developer IntellyWP
Plugin Icon 128x128 Inline Related Posts
Version 2.2.4
Comparing to
See all releases

Version 2.2.4

Files changed (125) hide show
  1. assets/css/style.css +154 -0
  2. assets/deps/qtip/jquery.qtip.min.js +21 -0
  3. assets/deps/select2-3.5.2/select2-bootstrap.css +87 -0
  4. assets/deps/select2-3.5.2/select2-spinner.gif +0 -0
  5. assets/deps/select2-3.5.2/select2.css +704 -0
  6. assets/deps/select2-3.5.2/select2.js +3541 -0
  7. assets/deps/select2-3.5.2/select2.min.js +23 -0
  8. assets/deps/select2-3.5.2/select2.png +0 -0
  9. assets/deps/select2-3.5.2/select2_locale_ar.js +19 -0
  10. assets/deps/select2-3.5.2/select2_locale_az.js +20 -0
  11. assets/deps/select2-3.5.2/select2_locale_bg.js +20 -0
  12. assets/deps/select2-3.5.2/select2_locale_ca.js +19 -0
  13. assets/deps/select2-3.5.2/select2_locale_cs.js +51 -0
  14. assets/deps/select2-3.5.2/select2_locale_da.js +19 -0
  15. assets/deps/select2-3.5.2/select2_locale_de.js +18 -0
  16. assets/deps/select2-3.5.2/select2_locale_el.js +19 -0
  17. assets/deps/select2-3.5.2/select2_locale_en.js.template +20 -0
  18. assets/deps/select2-3.5.2/select2_locale_es.js +19 -0
  19. assets/deps/select2-3.5.2/select2_locale_et.js +19 -0
  20. assets/deps/select2-3.5.2/select2_locale_eu.js +45 -0
  21. assets/deps/select2-3.5.2/select2_locale_fa.js +21 -0
  22. assets/deps/select2-3.5.2/select2_locale_fi.js +30 -0
  23. assets/deps/select2-3.5.2/select2_locale_fr.js +18 -0
  24. assets/deps/select2-3.5.2/select2_locale_gl.js +45 -0
  25. assets/deps/select2-3.5.2/select2_locale_he.js +19 -0
  26. assets/deps/select2-3.5.2/select2_locale_hr.js +24 -0
  27. assets/deps/select2-3.5.2/select2_locale_hu.js +17 -0
  28. assets/deps/select2-3.5.2/select2_locale_id.js +19 -0
  29. assets/deps/select2-3.5.2/select2_locale_is.js +17 -0
  30. assets/deps/select2-3.5.2/select2_locale_it.js +17 -0
  31. assets/deps/select2-3.5.2/select2_locale_ja.js +17 -0
  32. assets/deps/select2-3.5.2/select2_locale_ka.js +19 -0
  33. assets/deps/select2-3.5.2/select2_locale_ko.js +19 -0
  34. assets/deps/select2-3.5.2/select2_locale_lt.js +26 -0
  35. assets/deps/select2-3.5.2/select2_locale_lv.js +19 -0
  36. assets/deps/select2-3.5.2/select2_locale_mk.js +19 -0
  37. assets/deps/select2-3.5.2/select2_locale_ms.js +19 -0
  38. assets/deps/select2-3.5.2/select2_locale_nb.js +22 -0
  39. assets/deps/select2-3.5.2/select2_locale_nl.js +17 -0
  40. assets/deps/select2-3.5.2/select2_locale_pl.js +54 -0
  41. assets/deps/select2-3.5.2/select2_locale_pt-BR.js +18 -0
  42. assets/deps/select2-3.5.2/select2_locale_pt-PT.js +17 -0
  43. assets/deps/select2-3.5.2/select2_locale_ro.js +17 -0
  44. assets/deps/select2-3.5.2/select2_locale_rs.js +19 -0
  45. assets/deps/select2-3.5.2/select2_locale_ru.js +23 -0
  46. assets/deps/select2-3.5.2/select2_locale_sk.js +50 -0
  47. assets/deps/select2-3.5.2/select2_locale_sv.js +19 -0
  48. assets/deps/select2-3.5.2/select2_locale_th.js +19 -0
  49. assets/deps/select2-3.5.2/select2_locale_tr.js +19 -0
  50. assets/deps/select2-3.5.2/select2_locale_ug-CN.js +16 -0
  51. assets/deps/select2-3.5.2/select2_locale_uk.js +25 -0
  52. assets/deps/select2-3.5.2/select2_locale_vi.js +20 -0
  53. assets/deps/select2-3.5.2/select2_locale_zh-CN.js +16 -0
  54. assets/deps/select2-3.5.2/select2_locale_zh-TW.js +16 -0
  55. assets/deps/select2-3.5.2/select2x2.png +0 -0
  56. assets/deps/starrr/starrr.js +123 -0
  57. assets/images/button.png +0 -0
  58. assets/images/email.png +0 -0
  59. assets/images/heart.png +0 -0
  60. assets/images/internet.png +0 -0
  61. assets/images/iwp.png +0 -0
  62. assets/images/next-arrow.png +0 -0
  63. assets/images/question-mark.png +0 -0
  64. assets/images/repeat.png +0 -0
  65. assets/images/select-all.png +0 -0
  66. assets/images/simple-arrow.png +0 -0
  67. assets/images/tick.png +0 -0
  68. assets/images/twitter.png +0 -0
  69. assets/js/button-mce.js +45 -0
  70. assets/js/common.js +174 -0
  71. assets/landing/img-whatsnew.001.jpg +0 -0
  72. assets/landing/img-whatsnew.002.jpg +0 -0
  73. assets/landing/img-whatsnew.003.jpg +0 -0
  74. assets/landing/mac-irl-wahtsnew.png +0 -0
  75. assets/templates/preview-button.jpg +0 -0
  76. assets/templates/preview-kangoo.jpg +0 -0
  77. assets/templates/preview-ruby.jpg +0 -0
  78. assets/templates/styles.html +198 -0
  79. autoload.php +48 -0
  80. includes/actions.php +67 -0
  81. includes/admin/about.php +27 -0
  82. includes/admin/button-mce.php +134 -0
  83. includes/admin/faq.php +17 -0
  84. includes/admin/feedback.php +44 -0
  85. includes/admin/metabox.php +70 -0
  86. includes/admin/settings.php +417 -0
  87. includes/admin/whatsnew.php +105 -0
  88. includes/classes/common/Stack.php +27 -0
  89. includes/classes/core/HtmlTemplate.php +297 -0
  90. includes/classes/core/Manager.php +100 -0
  91. includes/classes/core/Singleton.php +36 -0
  92. includes/classes/html/BehaviourTag.php +51 -0
  93. includes/classes/html/HTMLContext.php +564 -0
  94. includes/classes/html/HTMLTag.php +61 -0
  95. includes/classes/html/MainTag.php +27 -0
  96. includes/classes/html/NewLineText.php +18 -0
  97. includes/classes/html/OtherTag.php +12 -0
  98. includes/classes/html/SingletonTag.php +15 -0
  99. includes/classes/html/TextContent.php +53 -0
  100. includes/classes/ui/Check.php +107 -0
  101. includes/classes/ui/Form.php +455 -0
  102. includes/classes/ui/Tabs.php +185 -0
  103. includes/classes/utils/AppOptions.php +422 -0
  104. includes/classes/utils/Cron.php +85 -0
  105. includes/classes/utils/Language.php +121 -0
  106. includes/classes/utils/Logger.php +119 -0
  107. includes/classes/utils/Options.php +261 -0
  108. includes/classes/utils/Plugin.php +263 -0
  109. includes/classes/utils/Tracking.php +191 -0
  110. includes/classes/utils/Utils.php +599 -0
  111. includes/core.php +335 -0
  112. includes/install.php +29 -0
  113. includes/uninstall.php +7 -0
  114. index.php +55 -0
  115. languages/Lang.txt +170 -0
  116. readme.txt +210 -0
  117. screenshot-1.gif +0 -0
  118. screenshot-2.png +0 -0
  119. screenshot-3.png +0 -0
  120. screenshot-4.png +0 -0
  121. screenshot-5.png +0 -0
  122. screenshot-6.jpg +0 -0
  123. screenshot-7.png +0 -0
  124. screenshot-8.png +0 -0
  125. screenshot-9.png +0 -0
assets/css/style.css ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ._irp {
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
+ .irp-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
+ .irp-tag-free {
28
+ /*background-color: #edb802;*/
29
+ background-color: #16a765;
30
+ }
31
+ .irp-tag-premium {
32
+ /*background-color: #edb802;*/
33
+ background-color: #4986e7;
34
+ opacity: 0.7;
35
+ filter: alpha(opacity=70);
36
+ }
37
+ .irp-tag-premium a {
38
+ color:white;
39
+ text-decoration:none;
40
+ }
41
+ .irp-button {
42
+ margin-right:5px!important;
43
+ }
44
+
45
+ .irp-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
+ .irp-form {
55
+ float:left;
56
+ padding:5px;
57
+ }
58
+ .irp-form input, .irp-form label {
59
+ float:left;
60
+ }
61
+ .irp-text {
62
+ width: 400px;
63
+ }
64
+ .irp-label {
65
+ width: 200px;
66
+ margin: 0px;
67
+ background-color: transparent;
68
+ }
69
+ .irp-label-disabled {
70
+ /*color:#A8A8A8;*/
71
+ opacity: 0.7;
72
+ filter: alpha(opacity=70);
73
+ }
74
+ .irp-checkbox {
75
+ margin:0px;
76
+ }
77
+ .irp-checkbox:disabled {
78
+ background-color: #f8f8f8;
79
+ }
80
+ .irp-select {
81
+
82
+ }
83
+ .irp-form-newline {
84
+ clear:both;
85
+ margin-bottom:5px;
86
+ }
87
+
88
+ img.irp-help {
89
+ cursor: pointer;
90
+ float: left;
91
+ margin-right: 10px;
92
+ }
93
+
94
+ .irp-qtip {
95
+ font-size: 14px !important;
96
+ line-height: 18px !important;
97
+ }
98
+
99
+ i.mce-i-icon {
100
+ font: 400 20px/1 dashicons;
101
+ padding: 0;
102
+ vertical-align: top;
103
+ speak: none;
104
+ -webkit-font-smoothing: antialiased;
105
+ -moz-osx-font-smoothing: grayscale;
106
+ margin-left: -2px;
107
+ padding-right: 2px
108
+ }
109
+
110
+ i.irp-own-icon {
111
+ background-image: url('../images/repeat.png');
112
+ }
113
+
114
+ .irp-box-error {
115
+ background: #fff;
116
+ border-left: 4px solid #dd3d36;
117
+ margin: 5px 0 15px;
118
+ -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
119
+ box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
120
+ padding: 1px 12px;
121
+ }
122
+ .irp-box-warning {
123
+ background: #fff;
124
+ border-left: 4px solid #ffba00;
125
+ margin: 5px 0 15px;
126
+ -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
127
+ box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
128
+ padding: 1px 12px;
129
+ }
130
+ .irp-box-success {
131
+ background: #fff;
132
+ border-left: 4px solid #7ad03a;
133
+ margin: 5px 0 15px;
134
+ -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
135
+ box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
136
+ padding: 1px 12px;
137
+ }
138
+ .irp-box-info {
139
+ background: #fff;
140
+ border-left: 4px solid #00a0d2;
141
+ margin: 5px 0 15px;
142
+ -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
143
+ box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
144
+ padding: 1px 12px;
145
+ }
146
+
147
+ .select2-chosen .irpColorSelectItem {
148
+ padding-bottom:0px!important;
149
+ padding-top:0px!important;
150
+ }
151
+ .irpColorSelectItem {
152
+ padding: 5px;
153
+ width: 100%;
154
+ }
assets/deps/qtip/jquery.qtip.min.js ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * jquery.qtip. The jQuery tooltip plugin
3
+ *
4
+ * Copyright (c) 2009 Craig Thompson
5
+ * http://craigsworks.com
6
+ *
7
+ * Licensed under MIT
8
+ * http://www.opensource.org/licenses/mit-license.php
9
+ *
10
+ * Launch : February 2009
11
+ * Version : 1.0.0-rc3
12
+ * Released: Tuesday 12th May, 2009 - 00:00
13
+ * Debug: jquery.qtip.debug.js
14
+ */
15
+ (function(f){f.fn.qtip=function(B,u){var y,t,A,s,x,w,v,z;if(typeof B=="string"){if(typeof f(this).data("qtip")!=="object"){f.fn.qtip.log.error.call(self,1,f.fn.qtip.constants.NO_TOOLTIP_PRESENT,false)}if(B=="api"){return f(this).data("qtip").interfaces[f(this).data("qtip").current]}else{if(B=="interfaces"){return f(this).data("qtip").interfaces}}}else{if(!B){B={}}if(typeof B.content!=="object"||(B.content.jquery&&B.content.length>0)){B.content={text:B.content}}if(typeof B.content.title!=="object"){B.content.title={text:B.content.title}}if(typeof B.position!=="object"){B.position={corner:B.position}}if(typeof B.position.corner!=="object"){B.position.corner={target:B.position.corner,tooltip:B.position.corner}}if(typeof B.show!=="object"){B.show={when:B.show}}if(typeof B.show.when!=="object"){B.show.when={event:B.show.when}}if(typeof B.show.effect!=="object"){B.show.effect={type:B.show.effect}}if(typeof B.hide!=="object"){B.hide={when:B.hide}}if(typeof B.hide.when!=="object"){B.hide.when={event:B.hide.when}}if(typeof B.hide.effect!=="object"){B.hide.effect={type:B.hide.effect}}if(typeof B.style!=="object"){B.style={name:B.style}}B.style=c(B.style);s=f.extend(true,{},f.fn.qtip.defaults,B);s.style=a.call({options:s},s.style);s.user=f.extend(true,{},B)}return f(this).each(function(){if(typeof B=="string"){w=B.toLowerCase();A=f(this).qtip("interfaces");if(typeof A=="object"){if(u===true&&w=="destroy"){while(A.length>0){A[A.length-1].destroy()}}else{if(u!==true){A=[f(this).qtip("api")]}for(y=0;y<A.length;y++){if(w=="destroy"){A[y].destroy()}else{if(A[y].status.rendered===true){if(w=="show"){A[y].show()}else{if(w=="hide"){A[y].hide()}else{if(w=="focus"){A[y].focus()}else{if(w=="disable"){A[y].disable(true)}else{if(w=="enable"){A[y].disable(false)}}}}}}}}}}}else{v=f.extend(true,{},s);v.hide.effect.length=s.hide.effect.length;v.show.effect.length=s.show.effect.length;if(v.position.container===false){v.position.container=f(document.body)}if(v.position.target===false){v.position.target=f(this)}if(v.show.when.target===false){v.show.when.target=f(this)}if(v.hide.when.target===false){v.hide.when.target=f(this)}t=f.fn.qtip.interfaces.length;for(y=0;y<t;y++){if(typeof f.fn.qtip.interfaces[y]=="undefined"){t=y;break}}x=new d(f(this),v,t);f.fn.qtip.interfaces[t]=x;if(typeof f(this).data("qtip")=="object"){if(typeof f(this).attr("qtip")==="undefined"){f(this).data("qtip").current=f(this).data("qtip").interfaces.length}f(this).data("qtip").interfaces.push(x)}else{f(this).data("qtip",{current:0,interfaces:[x]})}if(v.content.prerender===false&&v.show.when.event!==false&&v.show.ready!==true){v.show.when.target.bind(v.show.when.event+".qtip-"+t+"-create",{qtip:t},function(C){z=f.fn.qtip.interfaces[C.data.qtip];z.options.show.when.target.unbind(z.options.show.when.event+".qtip-"+C.data.qtip+"-create");z.cache.mouse={x:C.pageX,y:C.pageY};p.call(z);z.options.show.when.target.trigger(z.options.show.when.event)})}else{x.cache.mouse={x:v.show.when.target.offset().left,y:v.show.when.target.offset().top};p.call(x)}}})};function d(u,t,v){var s=this;s.id=v;s.options=t;s.status={animated:false,rendered:false,disabled:false,focused:false};s.elements={target:u.addClass(s.options.style.classes.target),tooltip:null,wrapper:null,content:null,contentWrapper:null,title:null,button:null,tip:null,bgiframe:null};s.cache={mouse:{},position:{},toggle:0};s.timers={};f.extend(s,s.options.api,{show:function(y){var x,z;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"show")}if(s.elements.tooltip.css("display")!=="none"){return s}s.elements.tooltip.stop(true,false);x=s.beforeShow.call(s,y);if(x===false){return s}function w(){if(s.options.position.type!=="static"){s.focus()}s.onShow.call(s,y);if(f.browser.msie){s.elements.tooltip.get(0).style.removeAttribute("filter")}}s.cache.toggle=1;if(s.options.position.type!=="static"){s.updatePosition(y,(s.options.show.effect.length>0))}if(typeof s.options.show.solo=="object"){z=f(s.options.show.solo)}else{if(s.options.show.solo===true){z=f("div.qtip").not(s.elements.tooltip)}}if(z){z.each(function(){if(f(this).qtip("api").status.rendered===true){f(this).qtip("api").hide()}})}if(typeof s.options.show.effect.type=="function"){s.options.show.effect.type.call(s.elements.tooltip,s.options.show.effect.length);s.elements.tooltip.queue(function(){w();f(this).dequeue()})}else{switch(s.options.show.effect.type.toLowerCase()){case"fade":s.elements.tooltip.fadeIn(s.options.show.effect.length,w);break;case"slide":s.elements.tooltip.slideDown(s.options.show.effect.length,function(){w();if(s.options.position.type!=="static"){s.updatePosition(y,true)}});break;case"grow":s.elements.tooltip.show(s.options.show.effect.length,w);break;default:s.elements.tooltip.show(null,w);break}s.elements.tooltip.addClass(s.options.style.classes.active)}return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_SHOWN,"show")},hide:function(y){var x;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"hide")}else{if(s.elements.tooltip.css("display")==="none"){return s}}clearTimeout(s.timers.show);s.elements.tooltip.stop(true,false);x=s.beforeHide.call(s,y);if(x===false){return s}function w(){s.onHide.call(s,y)}s.cache.toggle=0;if(typeof s.options.hide.effect.type=="function"){s.options.hide.effect.type.call(s.elements.tooltip,s.options.hide.effect.length);s.elements.tooltip.queue(function(){w();f(this).dequeue()})}else{switch(s.options.hide.effect.type.toLowerCase()){case"fade":s.elements.tooltip.fadeOut(s.options.hide.effect.length,w);break;case"slide":s.elements.tooltip.slideUp(s.options.hide.effect.length,w);break;case"grow":s.elements.tooltip.hide(s.options.hide.effect.length,w);break;default:s.elements.tooltip.hide(null,w);break}s.elements.tooltip.removeClass(s.options.style.classes.active)}return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_HIDDEN,"hide")},updatePosition:function(w,x){var C,G,L,J,H,E,y,I,B,D,K,A,F,z;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"updatePosition")}else{if(s.options.position.type=="static"){return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.CANNOT_POSITION_STATIC,"updatePosition")}}G={position:{left:0,top:0},dimensions:{height:0,width:0},corner:s.options.position.corner.target};L={position:s.getPosition(),dimensions:s.getDimensions(),corner:s.options.position.corner.tooltip};if(s.options.position.target!=="mouse"){if(s.options.position.target.get(0).nodeName.toLowerCase()=="area"){J=s.options.position.target.attr("coords").split(",");for(C=0;C<J.length;C++){J[C]=parseInt(J[C])}H=s.options.position.target.parent("map").attr("name");E=f('img[usemap="#'+H+'"]:first').offset();G.position={left:Math.floor(E.left+J[0]),top:Math.floor(E.top+J[1])};switch(s.options.position.target.attr("shape").toLowerCase()){case"rect":G.dimensions={width:Math.ceil(Math.abs(J[2]-J[0])),height:Math.ceil(Math.abs(J[3]-J[1]))};break;case"circle":G.dimensions={width:J[2]+1,height:J[2]+1};break;case"poly":G.dimensions={width:J[0],height:J[1]};for(C=0;C<J.length;C++){if(C%2==0){if(J[C]>G.dimensions.width){G.dimensions.width=J[C]}if(J[C]<J[0]){G.position.left=Math.floor(E.left+J[C])}}else{if(J[C]>G.dimensions.height){G.dimensions.height=J[C]}if(J[C]<J[1]){G.position.top=Math.floor(E.top+J[C])}}}G.dimensions.width=G.dimensions.width-(G.position.left-E.left);G.dimensions.height=G.dimensions.height-(G.position.top-E.top);break;default:return f.fn.qtip.log.error.call(s,4,f.fn.qtip.constants.INVALID_AREA_SHAPE,"updatePosition");break}G.dimensions.width-=2;G.dimensions.height-=2}else{if(s.options.position.target.add(document.body).length===1){G.position={left:f(document).scrollLeft(),top:f(document).scrollTop()};G.dimensions={height:f(window).height(),width:f(window).width()}}else{if(typeof s.options.position.target.attr("qtip")!=="undefined"){G.position=s.options.position.target.qtip("api").cache.position}else{G.position=s.options.position.target.offset()}G.dimensions={height:s.options.position.target.outerHeight(),width:s.options.position.target.outerWidth()}}}y=f.extend({},G.position);if(G.corner.search(/right/i)!==-1){y.left+=G.dimensions.width}if(G.corner.search(/bottom/i)!==-1){y.top+=G.dimensions.height}if(G.corner.search(/((top|bottom)Middle)|center/)!==-1){y.left+=(G.dimensions.width/2)}if(G.corner.search(/((left|right)Middle)|center/)!==-1){y.top+=(G.dimensions.height/2)}}else{G.position=y={left:s.cache.mouse.x,top:s.cache.mouse.y};G.dimensions={height:1,width:1}}if(L.corner.search(/right/i)!==-1){y.left-=L.dimensions.width}if(L.corner.search(/bottom/i)!==-1){y.top-=L.dimensions.height}if(L.corner.search(/((top|bottom)Middle)|center/)!==-1){y.left-=(L.dimensions.width/2)}if(L.corner.search(/((left|right)Middle)|center/)!==-1){y.top-=(L.dimensions.height/2)}I=(f.browser.msie)?1:0;B=(f.browser.msie&&parseInt(f.browser.version.charAt(0))===6)?1:0;if(s.options.style.border.radius>0){if(L.corner.search(/Left/)!==-1){y.left-=s.options.style.border.radius}else{if(L.corner.search(/Right/)!==-1){y.left+=s.options.style.border.radius}}if(L.corner.search(/Top/)!==-1){y.top-=s.options.style.border.radius}else{if(L.corner.search(/Bottom/)!==-1){y.top+=s.options.style.border.radius}}}if(I){if(L.corner.search(/top/)!==-1){y.top-=I}else{if(L.corner.search(/bottom/)!==-1){y.top+=I}}if(L.corner.search(/left/)!==-1){y.left-=I}else{if(L.corner.search(/right/)!==-1){y.left+=I}}if(L.corner.search(/leftMiddle|rightMiddle/)!==-1){y.top-=1}}if(s.options.position.adjust.screen===true){y=o.call(s,y,G,L)}if(s.options.position.target==="mouse"&&s.options.position.adjust.mouse===true){if(s.options.position.adjust.screen===true&&s.elements.tip){K=s.elements.tip.attr("rel")}else{K=s.options.position.corner.tooltip}y.left+=(K.search(/right/i)!==-1)?-6:6;y.top+=(K.search(/bottom/i)!==-1)?-6:6}if(!s.elements.bgiframe&&f.browser.msie&&parseInt(f.browser.version.charAt(0))==6){f("select, object").each(function(){A=f(this).offset();A.bottom=A.top+f(this).height();A.right=A.left+f(this).width();if(y.top+L.dimensions.height>=A.top&&y.left+L.dimensions.width>=A.left){k.call(s)}})}y.left+=s.options.position.adjust.x;y.top+=s.options.position.adjust.y;F=s.getPosition();if(y.left!=F.left||y.top!=F.top){z=s.beforePositionUpdate.call(s,w);if(z===false){return s}s.cache.position=y;if(x===true){s.status.animated=true;s.elements.tooltip.animate(y,200,"swing",function(){s.status.animated=false})}else{s.elements.tooltip.css(y)}s.onPositionUpdate.call(s,w);if(typeof w!=="undefined"&&w.type&&w.type!=="mousemove"){f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_POSITION_UPDATED,"updatePosition")}}return s},updateWidth:function(w){var x;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"updateWidth")}else{if(w&&typeof w!=="number"){return f.fn.qtip.log.error.call(s,2,"newWidth must be of type number","updateWidth")}}x=s.elements.contentWrapper.siblings().add(s.elements.tip).add(s.elements.button);if(!w){if(typeof s.options.style.width.value=="number"){w=s.options.style.width.value}else{s.elements.tooltip.css({width:"auto"});x.hide();if(f.browser.msie){s.elements.wrapper.add(s.elements.contentWrapper.children()).css({zoom:"normal"})}w=s.getDimensions().width+1;if(!s.options.style.width.value){if(w>s.options.style.width.max){w=s.options.style.width.max}if(w<s.options.style.width.min){w=s.options.style.width.min}}}}if(w%2!==0){w-=1}s.elements.tooltip.width(w);x.show();if(s.options.style.border.radius){s.elements.tooltip.find(".qtip-betweenCorners").each(function(y){f(this).width(w-(s.options.style.border.radius*2))})}if(f.browser.msie){s.elements.wrapper.add(s.elements.contentWrapper.children()).css({zoom:"1"});s.elements.wrapper.width(w);if(s.elements.bgiframe){s.elements.bgiframe.width(w).height(s.getDimensions.height)}}return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_WIDTH_UPDATED,"updateWidth")},updateStyle:function(w){var z,A,x,y,B;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"updateStyle")}else{if(typeof w!=="string"||!f.fn.qtip.styles[w]){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.STYLE_NOT_DEFINED,"updateStyle")}}s.options.style=a.call(s,f.fn.qtip.styles[w],s.options.user.style);s.elements.content.css(q(s.options.style));if(s.options.content.title.text!==false){s.elements.title.css(q(s.options.style.title,true))}s.elements.contentWrapper.css({borderColor:s.options.style.border.color});if(s.options.style.tip.corner!==false){if(f("<canvas>").get(0).getContext){z=s.elements.tooltip.find(".qtip-tip canvas:first");x=z.get(0).getContext("2d");x.clearRect(0,0,300,300);y=z.parent("div[rel]:first").attr("rel");B=b(y,s.options.style.tip.size.width,s.options.style.tip.size.height);h.call(s,z,B,s.options.style.tip.color||s.options.style.border.color)}else{if(f.browser.msie){z=s.elements.tooltip.find('.qtip-tip [nodeName="shape"]');z.attr("fillcolor",s.options.style.tip.color||s.options.style.border.color)}}}if(s.options.style.border.radius>0){s.elements.tooltip.find(".qtip-betweenCorners").css({backgroundColor:s.options.style.border.color});if(f("<canvas>").get(0).getContext){A=g(s.options.style.border.radius);s.elements.tooltip.find(".qtip-wrapper canvas").each(function(){x=f(this).get(0).getContext("2d");x.clearRect(0,0,300,300);y=f(this).parent("div[rel]:first").attr("rel");r.call(s,f(this),A[y],s.options.style.border.radius,s.options.style.border.color)})}else{if(f.browser.msie){s.elements.tooltip.find('.qtip-wrapper [nodeName="arc"]').each(function(){f(this).attr("fillcolor",s.options.style.border.color)})}}}return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_STYLE_UPDATED,"updateStyle")},updateContent:function(A,y){var z,x,w;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"updateContent")}else{if(!A){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.NO_CONTENT_PROVIDED,"updateContent")}}z=s.beforeContentUpdate.call(s,A);if(typeof z=="string"){A=z}else{if(z===false){return}}if(f.browser.msie){s.elements.contentWrapper.children().css({zoom:"normal"})}if(A.jquery&&A.length>0){A.clone(true).appendTo(s.elements.content).show()}else{s.elements.content.html(A)}x=s.elements.content.find("img[complete=false]");if(x.length>0){w=0;x.each(function(C){f('<img src="'+f(this).attr("src")+'" />').load(function(){if(++w==x.length){B()}})})}else{B()}function B(){s.updateWidth();if(y!==false){if(s.options.position.type!=="static"){s.updatePosition(s.elements.tooltip.is(":visible"),true)}if(s.options.style.tip.corner!==false){n.call(s)}}}s.onContentUpdate.call(s);return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_CONTENT_UPDATED,"loadContent")},loadContent:function(w,z,A){var y;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"loadContent")}y=s.beforeContentLoad.call(s);if(y===false){return s}if(A=="post"){f.post(w,z,x)}else{f.get(w,z,x)}function x(B){s.onContentLoad.call(s);f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_CONTENT_LOADED,"loadContent");s.updateContent(B)}return s},updateTitle:function(w){if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"updateTitle")}else{if(!w){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.NO_CONTENT_PROVIDED,"updateTitle")}}returned=s.beforeTitleUpdate.call(s);if(returned===false){return s}if(s.elements.button){s.elements.button=s.elements.button.clone(true)}s.elements.title.html(w);if(s.elements.button){s.elements.title.prepend(s.elements.button)}s.onTitleUpdate.call(s);return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_TITLE_UPDATED,"updateTitle")},focus:function(A){var y,x,w,z;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"focus")}else{if(s.options.position.type=="static"){return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.CANNOT_FOCUS_STATIC,"focus")}}y=parseInt(s.elements.tooltip.css("z-index"));x=6000+f("div.qtip[qtip]").length-1;if(!s.status.focused&&y!==x){z=s.beforeFocus.call(s,A);if(z===false){return s}f("div.qtip[qtip]").not(s.elements.tooltip).each(function(){if(f(this).qtip("api").status.rendered===true){w=parseInt(f(this).css("z-index"));if(typeof w=="number"&&w>-1){f(this).css({zIndex:parseInt(f(this).css("z-index"))-1})}f(this).qtip("api").status.focused=false}});s.elements.tooltip.css({zIndex:x});s.status.focused=true;s.onFocus.call(s,A);f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_FOCUSED,"focus")}return s},disable:function(w){if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"disable")}if(w){if(!s.status.disabled){s.status.disabled=true;f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_DISABLED,"disable")}else{f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.TOOLTIP_ALREADY_DISABLED,"disable")}}else{if(s.status.disabled){s.status.disabled=false;f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_ENABLED,"disable")}else{f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.TOOLTIP_ALREADY_ENABLED,"disable")}}return s},destroy:function(){var w,x,y;x=s.beforeDestroy.call(s);if(x===false){return s}if(s.status.rendered){s.options.show.when.target.unbind("mousemove.qtip",s.updatePosition);s.options.show.when.target.unbind("mouseout.qtip",s.hide);s.options.show.when.target.unbind(s.options.show.when.event+".qtip");s.options.hide.when.target.unbind(s.options.hide.when.event+".qtip");s.elements.tooltip.unbind(s.options.hide.when.event+".qtip");s.elements.tooltip.unbind("mouseover.qtip",s.focus);s.elements.tooltip.remove()}else{s.options.show.when.target.unbind(s.options.show.when.event+".qtip-create")}if(typeof s.elements.target.data("qtip")=="object"){y=s.elements.target.data("qtip").interfaces;if(typeof y=="object"&&y.length>0){for(w=0;w<y.length-1;w++){if(y[w].id==s.id){y.splice(w,1)}}}}delete f.fn.qtip.interfaces[s.id];if(typeof y=="object"&&y.length>0){s.elements.target.data("qtip").current=y.length-1}else{s.elements.target.removeData("qtip")}s.onDestroy.call(s);f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_DESTROYED,"destroy");return s.elements.target},getPosition:function(){var w,x;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"getPosition")}w=(s.elements.tooltip.css("display")!=="none")?false:true;if(w){s.elements.tooltip.css({visiblity:"hidden"}).show()}x=s.elements.tooltip.offset();if(w){s.elements.tooltip.css({visiblity:"visible"}).hide()}return x},getDimensions:function(){var w,x;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"getDimensions")}w=(!s.elements.tooltip.is(":visible"))?true:false;if(w){s.elements.tooltip.css({visiblity:"hidden"}).show()}x={height:s.elements.tooltip.outerHeight(),width:s.elements.tooltip.outerWidth()};if(w){s.elements.tooltip.css({visiblity:"visible"}).hide()}return x}})}function p(){var s,w,u,t,v,y,x;s=this;s.beforeRender.call(s);s.status.rendered=true;s.elements.tooltip='<div qtip="'+s.id+'" class="qtip '+(s.options.style.classes.tooltip||s.options.style)+'"style="display:none; -moz-border-radius:0; -webkit-border-radius:0; border-radius:0;position:'+s.options.position.type+';"> <div class="qtip-wrapper" style="position:relative; overflow:hidden; text-align:left;"> <div class="qtip-contentWrapper" style="overflow:hidden;"> <div class="qtip-content '+s.options.style.classes.content+'"></div></div></div></div>';s.elements.tooltip=f(s.elements.tooltip);s.elements.tooltip.appendTo(s.options.position.container);s.elements.tooltip.data("qtip",{current:0,interfaces:[s]});s.elements.wrapper=s.elements.tooltip.children("div:first");s.elements.contentWrapper=s.elements.wrapper.children("div:first").css({background:s.options.style.background});s.elements.content=s.elements.contentWrapper.children("div:first").css(q(s.options.style));if(f.browser.msie){s.elements.wrapper.add(s.elements.content).css({zoom:1})}if(s.options.hide.when.event=="unfocus"){s.elements.tooltip.attr("unfocus",true)}if(typeof s.options.style.width.value=="number"){s.updateWidth()}if(f("<canvas>").get(0).getContext||f.browser.msie){if(s.options.style.border.radius>0){m.call(s)}else{s.elements.contentWrapper.css({border:s.options.style.border.width+"px solid "+s.options.style.border.color})}if(s.options.style.tip.corner!==false){e.call(s)}}else{s.elements.contentWrapper.css({border:s.options.style.border.width+"px solid "+s.options.style.border.color});s.options.style.border.radius=0;s.options.style.tip.corner=false;f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.CANVAS_VML_NOT_SUPPORTED,"render")}if((typeof s.options.content.text=="string"&&s.options.content.text.length>0)||(s.options.content.text.jquery&&s.options.content.text.length>0)){u=s.options.content.text}else{if(typeof s.elements.target.attr("title")=="string"&&s.elements.target.attr("title").length>0){u=s.elements.target.attr("title").replace("\\n","<br />");s.elements.target.attr("title","")}else{if(typeof s.elements.target.attr("alt")=="string"&&s.elements.target.attr("alt").length>0){u=s.elements.target.attr("alt").replace("\\n","<br />");s.elements.target.attr("alt","")}else{u=" ";f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.NO_VALID_CONTENT,"render")}}}if(s.options.content.title.text!==false){j.call(s)}s.updateContent(u);l.call(s);if(s.options.show.ready===true){s.show()}if(s.options.content.url!==false){t=s.options.content.url;v=s.options.content.data;y=s.options.content.method||"get";s.loadContent(t,v,y)}s.onRender.call(s);f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_RENDERED,"render")}function m(){var F,z,t,B,x,E,u,G,D,y,w,C,A,s,v;F=this;F.elements.wrapper.find(".qtip-borderBottom, .qtip-borderTop").remove();t=F.options.style.border.width;B=F.options.style.border.radius;x=F.options.style.border.color||F.options.style.tip.color;E=g(B);u={};for(z in E){u[z]='<div rel="'+z+'" style="'+((z.search(/Left/)!==-1)?"left":"right")+":0; position:absolute; height:"+B+"px; width:"+B+'px; overflow:hidden; line-height:0.1px; font-size:1px">';if(f("<canvas>").get(0).getContext){u[z]+='<canvas height="'+B+'" width="'+B+'" style="vertical-align: top"></canvas>'}else{if(f.browser.msie){G=B*2+3;u[z]+='<v:arc stroked="false" fillcolor="'+x+'" startangle="'+E[z][0]+'" endangle="'+E[z][1]+'" style="width:'+G+"px; height:"+G+"px; margin-top:"+((z.search(/bottom/)!==-1)?-2:-1)+"px; margin-left:"+((z.search(/Right/)!==-1)?E[z][2]-3.5:-1)+'px; vertical-align:top; display:inline-block; behavior:url(#default#VML)"></v:arc>'}}u[z]+="</div>"}D=F.getDimensions().width-(Math.max(t,B)*2);y='<div class="qtip-betweenCorners" style="height:'+B+"px; width:"+D+"px; overflow:hidden; background-color:"+x+'; line-height:0.1px; font-size:1px;">';w='<div class="qtip-borderTop" dir="ltr" style="height:'+B+"px; margin-left:"+B+'px; line-height:0.1px; font-size:1px; padding:0;">'+u.topLeft+u.topRight+y;F.elements.wrapper.prepend(w);C='<div class="qtip-borderBottom" dir="ltr" style="height:'+B+"px; margin-left:"+B+'px; line-height:0.1px; font-size:1px; padding:0;">'+u.bottomLeft+u.bottomRight+y;F.elements.wrapper.append(C);if(f("<canvas>").get(0).getContext){F.elements.wrapper.find("canvas").each(function(){A=E[f(this).parent("[rel]:first").attr("rel")];r.call(F,f(this),A,B,x)})}else{if(f.browser.msie){F.elements.tooltip.append('<v:image style="behavior:url(#default#VML);"></v:image>')}}s=Math.max(B,(B+(t-B)));v=Math.max(t-B,0);F.elements.contentWrapper.css({border:"0px solid "+x,borderWidth:v+"px "+s+"px"})}function r(u,w,s,t){var v=u.get(0).getContext("2d");v.fillStyle=t;v.beginPath();v.arc(w[0],w[1],s,0,Math.PI*2,false);v.fill()}function e(v){var t,s,x,u,w;t=this;if(t.elements.tip!==null){t.elements.tip.remove()}s=t.options.style.tip.color||t.options.style.border.color;if(t.options.style.tip.corner===false){return}else{if(!v){v=t.options.style.tip.corner}}x=b(v,t.options.style.tip.size.width,t.options.style.tip.size.height);t.elements.tip='<div class="'+t.options.style.classes.tip+'" dir="ltr" rel="'+v+'" style="position:absolute; height:'+t.options.style.tip.size.height+"px; width:"+t.options.style.tip.size.width+'px; margin:0 auto; line-height:0.1px; font-size:1px;">';if(f("<canvas>").get(0).getContext){t.elements.tip+='<canvas height="'+t.options.style.tip.size.height+'" width="'+t.options.style.tip.size.width+'"></canvas>'}else{if(f.browser.msie){u=t.options.style.tip.size.width+","+t.options.style.tip.size.height;w="m"+x[0][0]+","+x[0][1];w+=" l"+x[1][0]+","+x[1][1];w+=" "+x[2][0]+","+x[2][1];w+=" xe";t.elements.tip+='<v:shape fillcolor="'+s+'" stroked="false" filled="true" path="'+w+'" coordsize="'+u+'" style="width:'+t.options.style.tip.size.width+"px; height:"+t.options.style.tip.size.height+"px; line-height:0.1px; display:inline-block; behavior:url(#default#VML); vertical-align:"+((v.search(/top/)!==-1)?"bottom":"top")+'"></v:shape>';t.elements.tip+='<v:image style="behavior:url(#default#VML);"></v:image>';t.elements.contentWrapper.css("position","relative")}}t.elements.tooltip.prepend(t.elements.tip+"</div>");t.elements.tip=t.elements.tooltip.find("."+t.options.style.classes.tip).eq(0);if(f("<canvas>").get(0).getContext){h.call(t,t.elements.tip.find("canvas:first"),x,s)}if(v.search(/top/)!==-1&&f.browser.msie&&parseInt(f.browser.version.charAt(0))===6){t.elements.tip.css({marginTop:-4})}n.call(t,v)}function h(t,v,s){var u=t.get(0).getContext("2d");u.fillStyle=s;u.beginPath();u.moveTo(v[0][0],v[0][1]);u.lineTo(v[1][0],v[1][1]);u.lineTo(v[2][0],v[2][1]);u.fill()}function n(u){var t,w,s,x,v;t=this;if(t.options.style.tip.corner===false||!t.elements.tip){return}if(!u){u=t.elements.tip.attr("rel")}w=positionAdjust=(f.browser.msie)?1:0;t.elements.tip.css(u.match(/left|right|top|bottom/)[0],0);if(u.search(/top|bottom/)!==-1){if(f.browser.msie){if(parseInt(f.browser.version.charAt(0))===6){positionAdjust=(u.search(/top/)!==-1)?-3:1}else{positionAdjust=(u.search(/top/)!==-1)?1:2}}if(u.search(/Middle/)!==-1){t.elements.tip.css({left:"50%",marginLeft:-(t.options.style.tip.size.width/2)})}else{if(u.search(/Left/)!==-1){t.elements.tip.css({left:t.options.style.border.radius-w})}else{if(u.search(/Right/)!==-1){t.elements.tip.css({right:t.options.style.border.radius+w})}}}if(u.search(/top/)!==-1){t.elements.tip.css({top:-positionAdjust})}else{t.elements.tip.css({bottom:positionAdjust})}}else{if(u.search(/left|right/)!==-1){if(f.browser.msie){positionAdjust=(parseInt(f.browser.version.charAt(0))===6)?1:((u.search(/left/)!==-1)?1:2)}if(u.search(/Middle/)!==-1){t.elements.tip.css({top:"50%",marginTop:-(t.options.style.tip.size.height/2)})}else{if(u.search(/Top/)!==-1){t.elements.tip.css({top:t.options.style.border.radius-w})}else{if(u.search(/Bottom/)!==-1){t.elements.tip.css({bottom:t.options.style.border.radius+w})}}}if(u.search(/left/)!==-1){t.elements.tip.css({left:-positionAdjust})}else{t.elements.tip.css({right:positionAdjust})}}}s="padding-"+u.match(/left|right|top|bottom/)[0];x=t.options.style.tip.size[(s.search(/left|right/)!==-1)?"width":"height"];t.elements.tooltip.css("padding",0);t.elements.tooltip.css(s,x);if(f.browser.msie&&parseInt(f.browser.version.charAt(0))==6){v=parseInt(t.elements.tip.css("margin-top"))||0;v+=parseInt(t.elements.content.css("margin-top"))||0;t.elements.tip.css({marginTop:v})}}function j(){var s=this;if(s.elements.title!==null){s.elements.title.remove()}s.elements.title=f('<div class="'+s.options.style.classes.title+'">').css(q(s.options.style.title,true)).css({zoom:(f.browser.msie)?1:0}).prependTo(s.elements.contentWrapper);if(s.options.content.title.text){s.updateTitle.call(s,s.options.content.title.text)}if(s.options.content.title.button!==false&&typeof s.options.content.title.button=="string"){s.elements.button=f('<a class="'+s.options.style.classes.button+'" style="float:right; position: relative"></a>').css(q(s.options.style.button,true)).html(s.options.content.title.button).prependTo(s.elements.title).click(function(t){if(!s.status.disabled){s.hide(t)}})}}function l(){var t,v,u,s;t=this;v=t.options.show.when.target;u=t.options.hide.when.target;if(t.options.hide.fixed){u=u.add(t.elements.tooltip)}if(t.options.hide.when.event=="inactive"){s=["click","dblclick","mousedown","mouseup","mousemove","mouseout","mouseenter","mouseleave","mouseover"];function y(z){if(t.status.disabled===true){return}clearTimeout(t.timers.inactive);t.timers.inactive=setTimeout(function(){f(s).each(function(){u.unbind(this+".qtip-inactive");t.elements.content.unbind(this+".qtip-inactive")});t.hide(z)},t.options.hide.delay)}}else{if(t.options.hide.fixed===true){t.elements.tooltip.bind("mouseover.qtip",function(){if(t.status.disabled===true){return}clearTimeout(t.timers.hide)})}}function x(z){if(t.status.disabled===true){return}if(t.options.hide.when.event=="inactive"){f(s).each(function(){u.bind(this+".qtip-inactive",y);t.elements.content.bind(this+".qtip-inactive",y)});y()}clearTimeout(t.timers.show);clearTimeout(t.timers.hide);t.timers.show=setTimeout(function(){t.show(z)},t.options.show.delay)}function w(z){if(t.status.disabled===true){return}if(t.options.hide.fixed===true&&t.options.hide.when.event.search(/mouse(out|leave)/i)!==-1&&f(z.relatedTarget).parents("div.qtip[qtip]").length>0){z.stopPropagation();z.preventDefault();clearTimeout(t.timers.hide);return false}clearTimeout(t.timers.show);clearTimeout(t.timers.hide);t.elements.tooltip.stop(true,true);t.timers.hide=setTimeout(function(){t.hide(z)},t.options.hide.delay)}if((t.options.show.when.target.add(t.options.hide.when.target).length===1&&t.options.show.when.event==t.options.hide.when.event&&t.options.hide.when.event!=="inactive")||t.options.hide.when.event=="unfocus"){t.cache.toggle=0;v.bind(t.options.show.when.event+".qtip",function(z){if(t.cache.toggle==0){x(z)}else{w(z)}})}else{v.bind(t.options.show.when.event+".qtip",x);if(t.options.hide.when.event!=="inactive"){u.bind(t.options.hide.when.event+".qtip",w)}}if(t.options.position.type.search(/(fixed|absolute)/)!==-1){t.elements.tooltip.bind("mouseover.qtip",t.focus)}if(t.options.position.target==="mouse"&&t.options.position.type!=="static"){v.bind("mousemove.qtip",function(z){t.cache.mouse={x:z.pageX,y:z.pageY};if(t.status.disabled===false&&t.options.position.adjust.mouse===true&&t.options.position.type!=="static"&&t.elements.tooltip.css("display")!=="none"){t.updatePosition(z)}})}}function o(u,v,A){var z,s,x,y,t,w;z=this;if(A.corner=="center"){return v.position}s=f.extend({},u);y={x:false,y:false};t={left:(s.left<f.fn.qtip.cache.screen.scroll.left),right:(s.left+A.dimensions.width+2>=f.fn.qtip.cache.screen.width+f.fn.qtip.cache.screen.scroll.left),top:(s.top<f.fn.qtip.cache.screen.scroll.top),bottom:(s.top+A.dimensions.height+2>=f.fn.qtip.cache.screen.height+f.fn.qtip.cache.screen.scroll.top)};x={left:(t.left&&(A.corner.search(/right/i)!=-1||(A.corner.search(/right/i)==-1&&!t.right))),right:(t.right&&(A.corner.search(/left/i)!=-1||(A.corner.search(/left/i)==-1&&!t.left))),top:(t.top&&A.corner.search(/top/i)==-1),bottom:(t.bottom&&A.corner.search(/bottom/i)==-1)};if(x.left){if(z.options.position.target!=="mouse"){s.left=v.position.left+v.dimensions.width}else{s.left=z.cache.mouse.x}y.x="Left"}else{if(x.right){if(z.options.position.target!=="mouse"){s.left=v.position.left-A.dimensions.width}else{s.left=z.cache.mouse.x-A.dimensions.width}y.x="Right"}}if(x.top){if(z.options.position.target!=="mouse"){s.top=v.position.top+v.dimensions.height}else{s.top=z.cache.mouse.y}y.y="top"}else{if(x.bottom){if(z.options.position.target!=="mouse"){s.top=v.position.top-A.dimensions.height}else{s.top=z.cache.mouse.y-A.dimensions.height}y.y="bottom"}}if(s.left<0){s.left=u.left;y.x=false}if(s.top<0){s.top=u.top;y.y=false}if(z.options.style.tip.corner!==false){s.corner=new String(A.corner);if(y.x!==false){s.corner=s.corner.replace(/Left|Right|Middle/,y.x)}if(y.y!==false){s.corner=s.corner.replace(/top|bottom/,y.y)}if(s.corner!==z.elements.tip.attr("rel")){e.call(z,s.corner)}}return s}function q(u,t){var v,s;v=f.extend(true,{},u);for(s in v){if(t===true&&s.search(/(tip|classes)/i)!==-1){delete v[s]}else{if(!t&&s.search(/(width|border|tip|title|classes|user)/i)!==-1){delete v[s]}}}return v}function c(s){if(typeof s.tip!=="object"){s.tip={corner:s.tip}}if(typeof s.tip.size!=="object"){s.tip.size={width:s.tip.size,height:s.tip.size}}if(typeof s.border!=="object"){s.border={width:s.border}}if(typeof s.width!=="object"){s.width={value:s.width}}if(typeof s.width.max=="string"){s.width.max=parseInt(s.width.max.replace(/([0-9]+)/i,"$1"))}if(typeof s.width.min=="string"){s.width.min=parseInt(s.width.min.replace(/([0-9]+)/i,"$1"))}if(typeof s.tip.size.x=="number"){s.tip.size.width=s.tip.size.x;delete s.tip.size.x}if(typeof s.tip.size.y=="number"){s.tip.size.height=s.tip.size.y;delete s.tip.size.y}return s}function a(){var s,t,u,x,v,w;s=this;u=[true,{}];for(t=0;t<arguments.length;t++){u.push(arguments[t])}x=[f.extend.apply(f,u)];while(typeof x[0].name=="string"){x.unshift(c(f.fn.qtip.styles[x[0].name]))}x.unshift(true,{classes:{tooltip:"qtip-"+(arguments[0].name||"defaults")}},f.fn.qtip.styles.defaults);v=f.extend.apply(f,x);w=(f.browser.msie)?1:0;v.tip.size.width+=w;v.tip.size.height+=w;if(v.tip.size.width%2>0){v.tip.size.width+=1}if(v.tip.size.height%2>0){v.tip.size.height+=1}if(v.tip.corner===true){v.tip.corner=(s.options.position.corner.tooltip==="center")?false:s.options.position.corner.tooltip}return v}function b(v,u,t){var s={bottomRight:[[0,0],[u,t],[u,0]],bottomLeft:[[0,0],[u,0],[0,t]],topRight:[[0,t],[u,0],[u,t]],topLeft:[[0,0],[0,t],[u,t]],topMiddle:[[0,t],[u/2,0],[u,t]],bottomMiddle:[[0,0],[u,0],[u/2,t]],rightMiddle:[[0,0],[u,t/2],[0,t]],leftMiddle:[[u,0],[u,t],[0,t/2]]};s.leftTop=s.bottomRight;s.rightTop=s.bottomLeft;s.leftBottom=s.topRight;s.rightBottom=s.topLeft;return s[v]}function g(s){var t;if(f("<canvas>").get(0).getContext){t={topLeft:[s,s],topRight:[0,s],bottomLeft:[s,0],bottomRight:[0,0]}}else{if(f.browser.msie){t={topLeft:[-90,90,0],topRight:[-90,90,-s],bottomLeft:[90,270,0],bottomRight:[90,270,-s]}}}return t}function k(){var s,t,u;s=this;u=s.getDimensions();t='<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:false" style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=\'0\'); border: 1px solid red; height:'+u.height+"px; width:"+u.width+'px" />';s.elements.bgiframe=s.elements.wrapper.prepend(t).children(".qtip-bgiframe:first")}f(document).ready(function(){f.fn.qtip.cache={screen:{scroll:{left:f(window).scrollLeft(),top:f(window).scrollTop()},width:f(window).width(),height:f(window).height()}};var s;f(window).bind("resize scroll",function(t){clearTimeout(s);s=setTimeout(function(){if(t.type==="scroll"){f.fn.qtip.cache.screen.scroll={left:f(window).scrollLeft(),top:f(window).scrollTop()}}else{f.fn.qtip.cache.screen.width=f(window).width();f.fn.qtip.cache.screen.height=f(window).height()}for(i=0;i<f.fn.qtip.interfaces.length;i++){var u=f.fn.qtip.interfaces[i];if(u.status.rendered===true&&(u.options.position.type!=="static"||u.options.position.adjust.scroll&&t.type==="scroll"||u.options.position.adjust.resize&&t.type==="resize")){u.updatePosition(t,true)}}},100)});f(document).bind("mousedown.qtip",function(t){if(f(t.target).parents("div.qtip").length===0){f(".qtip[unfocus]").each(function(){var u=f(this).qtip("api");if(f(this).is(":visible")&&!u.status.disabled&&f(t.target).add(u.elements.target).length>1){u.hide(t)}})}})});f.fn.qtip.interfaces=[];f.fn.qtip.log={error:function(){return this}};f.fn.qtip.constants={};f.fn.qtip.defaults={content:{prerender:false,text:false,url:false,data:null,title:{text:false,button:false}},position:{target:false,corner:{target:"bottomRight",tooltip:"topLeft"},adjust:{x:0,y:0,mouse:true,screen:false,scroll:true,resize:true},type:"absolute",container:false},show:{when:{target:false,event:"mouseover"},effect:{type:"fade",length:100},delay:140,solo:false,ready:false},hide:{when:{target:false,event:"mouseout"},effect:{type:"fade",length:100},delay:0,fixed:false},api:{beforeRender:function(){},onRender:function(){},beforePositionUpdate:function(){},onPositionUpdate:function(){},beforeShow:function(){},onShow:function(){},beforeHide:function(){},onHide:function(){},beforeContentUpdate:function(){},onContentUpdate:function(){},beforeContentLoad:function(){},onContentLoad:function(){},beforeTitleUpdate:function(){},onTitleUpdate:function(){},beforeDestroy:function(){},onDestroy:function(){},beforeFocus:function(){},onFocus:function(){}}};f.fn.qtip.styles={defaults:{background:"white",color:"#111",overflow:"hidden",textAlign:"left",width:{min:0,max:250},padding:"5px 9px",border:{width:1,radius:0,color:"#d3d3d3"},tip:{corner:false,color:false,size:{width:13,height:13},opacity:1},title:{background:"#e1e1e1",fontWeight:"bold",padding:"7px 12px"},button:{cursor:"pointer"},classes:{target:"",tip:"qtip-tip",title:"qtip-title",button:"qtip-button",content:"qtip-content",active:"qtip-active"}},cream:{border:{width:3,radius:0,color:"#F9E98E"},title:{background:"#F0DE7D",color:"#A27D35"},background:"#FBF7AA",color:"#A27D35",classes:{tooltip:"qtip-cream"}},light:{border:{width:3,radius:0,color:"#E2E2E2"},title:{background:"#f1f1f1",color:"#454545"},background:"white",color:"#454545",classes:{tooltip:"qtip-light"}},dark:{border:{width:3,radius:0,color:"#303030"},title:{background:"#404040",color:"#f3f3f3"},background:"#505050",color:"#f3f3f3",classes:{tooltip:"qtip-dark"}},red:{border:{width:3,radius:0,color:"#CE6F6F"},title:{background:"#f28279",color:"#9C2F2F"},background:"#F79992",color:"#9C2F2F",classes:{tooltip:"qtip-red"}},green:{border:{width:3,radius:0,color:"#A9DB66"},title:{background:"#b9db8c",color:"#58792E"},background:"#CDE6AC",color:"#58792E",classes:{tooltip:"qtip-green"}},blue:{border:{width:3,radius:0,color:"#ADD9ED"},title:{background:"#D0E9F5",color:"#5E99BD"},background:"#E5F6FE",color:"#4D9FBF",classes:{tooltip:"qtip-blue"}}}})(jQuery);
16
+
17
+
18
+
19
+
20
+
21
+
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.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/deps/starrr/starrr.js ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var __slice = [].slice;
2
+
3
+ (function(jQuery, window) {
4
+ var Starrr;
5
+ window.Starrr = Starrr = (function() {
6
+ Starrr.prototype.defaults = {
7
+ rating: void 0,
8
+ numStars: 5,
9
+ emptyStarClass: 'fa fa-star-o',
10
+ fullStarClass: 'fa fa-star',
11
+ change: function(e, value) {}
12
+ };
13
+
14
+ function Starrr($el, options) {
15
+ var i, _, _ref;
16
+ this.options = jQuery.extend({}, this.defaults, options);
17
+ this.$el = $el;
18
+ _ref = this.defaults;
19
+ for (i in _ref) {
20
+ _ = _ref[i];
21
+ if (this.$el.data(i.toLowerCase()) != null) {
22
+ this.options[i] = this.$el.data(i.toLowerCase());
23
+ }
24
+ }
25
+ if (this.$el.data('connected-input')) {
26
+ this.$connectedInput = jQuery("[name=\"" + (this.$el.data('connected-input')) + "\"]");
27
+ this.options.rating = this.$connectedInput.val() ? parseInt(this.$connectedInput.val(), 10) : void 0;
28
+ }
29
+ this.createStars();
30
+ this.syncRating();
31
+ if (this.$connectedInput && this.$connectedInput.is(':disabled')) {
32
+ return;
33
+ }
34
+ this.$el.on('mouseover.starrr', 'i', (function(_this) {
35
+ return function(e) {
36
+ return _this.syncRating(_this.getStars().index(e.currentTarget) + 1);
37
+ };
38
+ })(this));
39
+ this.$el.on('mouseout.starrr', (function(_this) {
40
+ return function() {
41
+ return _this.syncRating();
42
+ };
43
+ })(this));
44
+ this.$el.on('click.starrr', 'i', (function(_this) {
45
+ return function(e) {
46
+ return _this.setRating(_this.getStars().index(e.currentTarget) + 1);
47
+ };
48
+ })(this));
49
+ this.$el.on('starrr:change', this.options.change);
50
+ if (this.$connectedInput != null) {
51
+ this.$el.on('starrr:change', (function(_this) {
52
+ return function(e, value) {
53
+ _this.$connectedInput.val(value);
54
+ return _this.$connectedInput.trigger('focusout');
55
+ };
56
+ })(this));
57
+ }
58
+ }
59
+
60
+ Starrr.prototype.getStars = function() {
61
+ return this.$el.find('i');
62
+ };
63
+
64
+ Starrr.prototype.createStars = function() {
65
+ var _i, _ref, _results;
66
+ _results = [];
67
+ for (_i = 1, _ref = this.options.numStars; 1 <= _ref ? _i <= _ref : _i >= _ref; 1 <= _ref ? _i++ : _i--) {
68
+ _results.push(this.$el.append("<i class='" + this.options.emptyStarClass + "'></i>"));
69
+ }
70
+ return _results;
71
+ };
72
+
73
+ Starrr.prototype.setRating = function(rating) {
74
+ if (this.options.rating === rating) {
75
+ rating = void 0;
76
+ }
77
+ this.options.rating = rating;
78
+ this.syncRating();
79
+ return this.$el.trigger('starrr:change', rating);
80
+ };
81
+
82
+ Starrr.prototype.getRating = function() {
83
+ return this.options.rating;
84
+ };
85
+
86
+ Starrr.prototype.syncRating = function(rating) {
87
+ var i, _i, _j, _ref, _ref1;
88
+ rating || (rating = this.options.rating);
89
+ if (rating) {
90
+ for (i = _i = 0, _ref = rating - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
91
+ this.getStars().eq(i).removeClass(this.options.emptyStarClass).addClass(this.options.fullStarClass);
92
+ }
93
+ }
94
+ if (rating && rating < this.options.numStars) {
95
+ for (i = _j = rating, _ref1 = this.options.numStars - 1; rating <= _ref1 ? _j <= _ref1 : _j >= _ref1; i = rating <= _ref1 ? ++_j : --_j) {
96
+ this.getStars().eq(i).removeClass(this.options.fullStarClass).addClass(this.options.emptyStarClass);
97
+ }
98
+ }
99
+ if (!rating) {
100
+ return this.getStars().removeClass(this.options.fullStarClass).addClass(this.options.emptyStarClass);
101
+ }
102
+ };
103
+
104
+ return Starrr;
105
+
106
+ })();
107
+ return jQuery.fn.extend({
108
+ starrr: function() {
109
+ var args, option;
110
+ option = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
111
+ return this.each(function() {
112
+ var data;
113
+ data = jQuery(this).data('starrr');
114
+ if (!data) {
115
+ jQuery(this).data('starrr', (data = new Starrr(jQuery(this), option)));
116
+ }
117
+ if (typeof option === 'string') {
118
+ return data[option].apply(data, args);
119
+ }
120
+ });
121
+ }
122
+ });
123
+ })(window.jQuery, window);
assets/images/button.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/iwp.png ADDED
Binary file
assets/images/next-arrow.png ADDED
Binary file
assets/images/question-mark.png ADDED
Binary file
assets/images/repeat.png ADDED
Binary file
assets/images/select-all.png ADDED
Binary file
assets/images/simple-arrow.png ADDED
Binary file
assets/images/tick.png ADDED
Binary file
assets/images/twitter.png ADDED
Binary file
assets/js/button-mce.js ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function() {
2
+ tinymce.PluginManager.add('irp_mce_button', function(editor, url) {
3
+ editor.addButton('irp_mce_button', {
4
+ title: 'Inline Related Posts PRO'
5
+ , type: 'menubutton'
6
+ , icon: 'icon irp-own-icon'
7
+ , image : url + '/../images/repeat.png'
8
+ , menu: [
9
+ {
10
+ text: 'Inline Related Post'
11
+ , onclick: function() {
12
+ var code='[irp]';
13
+ editor.insertContent(code);
14
+ }
15
+ }
16
+ , {
17
+ text: 'Custom Related Post'
18
+ , onclick: function() {
19
+ editor.windowManager.open({
20
+ title: 'Choose a post'
21
+ , width: 350
22
+ , height: 250
23
+ , file: ajaxurl+'?action=do_action&irp_action=ui_button_editor&irp_post_type=post'
24
+ , inline: 1
25
+ , resizable: false
26
+ });
27
+ }
28
+ }
29
+ , {
30
+ text: 'Custom Related Page'
31
+ , onclick: function() {
32
+ editor.windowManager.open({
33
+ title: 'Choose a page'
34
+ , width: 350
35
+ , height: 250
36
+ , file: ajaxurl+'?action=do_action&irp_action=ui_button_editor&irp_post_type=page'
37
+ , inline: 1
38
+ , resizable: false
39
+ });
40
+ }
41
+ }
42
+ ]
43
+ });
44
+ });
45
+ })();
assets/js/common.js ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //IntellyWP
2
+ jQuery('.wrap .updated.fade').remove();
3
+ jQuery('.woocommerce-message').remove();
4
+ jQuery('.error').remove();
5
+ jQuery('.info').remove();
6
+ jQuery('.update-nag').remove();
7
+
8
+ jQuery(function() {
9
+ "use strict";
10
+ //WooCommerce errors
11
+ var removeWooUpdateTheme = setInterval(function () {
12
+ if (jQuery('.wrap .updated.fade').length > 0) {
13
+ jQuery('.wrap .updated.fade').remove();
14
+ clearInterval(removeWooUpdateTheme);
15
+ }
16
+ }, 100);
17
+ var removeWooMessage = setInterval(function () {
18
+ if (jQuery('.woocommerce-message').length > 0) {
19
+ jQuery('.woocommerce-message').remove();
20
+ clearInterval(removeWooMessage);
21
+ }
22
+ }, 100);
23
+
24
+ jQuery('.wrap .updated.fade').remove();
25
+ jQuery('.woocommerce-message').remove();
26
+ jQuery('.error').remove();
27
+ jQuery('.info').remove();
28
+ jQuery('.update-nag').remove();
29
+ });
30
+
31
+ function IRP_stripos(haystack, needle, offset) {
32
+ // discuss at: http://phpjs.org/functions/stripos/
33
+ // original by: Martijn Wieringa
34
+ // revised by: Onno Marsman
35
+ // example 1: stripos('ABC', 'a');
36
+ // returns 1: 0
37
+
38
+ var haystack = (haystack + '').toLowerCase();
39
+ var needle = (needle + '').toLowerCase();
40
+ var index = 0;
41
+
42
+ if ((index = haystack.indexOf(needle, offset)) !== -1) {
43
+ return index;
44
+ }
45
+ return false;
46
+ }
47
+ function IRP_val(name) {
48
+ return jQuery('[name='+name+']').val();
49
+ }
50
+ function IRP_check(name) {
51
+ return (jQuery('[name='+name+']').is(':checked') ? 1 : 0);
52
+ }
53
+ function IRP_radio(name) {
54
+ return (jQuery('[name='+name+']:checked').val());
55
+ }
56
+ function IRP_visible(name, visible) {
57
+ if(visible) {
58
+ jQuery(name).hide();
59
+ } else {
60
+ jQuery(name).show();
61
+ }
62
+ }
63
+ function IRP_aval(name) {
64
+ var data={};
65
+ jQuery("[name^='"+name+"']").each(function(i,v) {
66
+ var $this=jQuery(this);
67
+ var k=$this.attr('name');
68
+ var v=$this.val();
69
+ if($this.attr('type')=='checkbox') {
70
+ v=IRP_check(k);
71
+ } else if($this.attr('type')=='radio') {
72
+ v=IRP_radio(k);
73
+ }
74
+ data[k]=v;
75
+ });
76
+ //console.log(data);
77
+ return data;
78
+ }
79
+ function IRP_formatColorOption(option) {
80
+ if (!option.id) {
81
+ return option.text;
82
+ }
83
+
84
+ var color=jQuery(option.element).css('background-color');
85
+ var font=jQuery(option.element).css('color');
86
+ var $option = jQuery('<div></div>')
87
+ .html(option.text)
88
+ .css('background-color', color)
89
+ .css('color', font)
90
+ .addClass('irpColorSelectItem');
91
+ return $option;
92
+ }
93
+ function IRP_hideShow(v) {
94
+ var $source = jQuery(v);
95
+ if ($source.attr('irp-hideIfTrue') && $source.attr('irp-hideShow')) {
96
+ var $destination = jQuery('[name=' + $source.attr('irp-hideShow') + ']');
97
+ if ($destination.length == 0) {
98
+ $destination = jQuery('#' + $source.attr('irp-hideShow'));
99
+ }
100
+ if ($destination.length > 0) {
101
+ var isChecked = $source.is(":checked");
102
+ var hideIfTrue = ($source.attr('irp-hideIfTrue').toLowerCase() == 'true');
103
+
104
+ if (isChecked) {
105
+ if (hideIfTrue) {
106
+ $destination.hide();
107
+ } else {
108
+ $destination.show();
109
+ }
110
+ } else {
111
+ if (hideIfTrue) {
112
+ $destination.show();
113
+ } else {
114
+ $destination.hide();
115
+ }
116
+ }
117
+ }
118
+ }
119
+ }
120
+
121
+ jQuery(function() {
122
+ jQuery(".irp-hideShow").click(function () {
123
+ IRP_hideShow(this);
124
+ });
125
+ jQuery(".irp-hideShow").each(function () {
126
+ IRP_hideShow(this);
127
+ });
128
+
129
+ if(jQuery(".irpTags").length>0) {
130
+ jQuery(".irpTags").select2({
131
+ placeholder: "Type here..."
132
+ , theme: "classic"
133
+ , width: '300px'
134
+ });
135
+ }
136
+
137
+ if(jQuery(".irpColorSelect").length>0) {
138
+ jQuery(".irpColorSelect").select2({
139
+ placeholder: "Type here..."
140
+ , theme: "classic"
141
+ , width: '300px'
142
+ , formatResult: IRP_formatColorOption
143
+ , formatSelection: IRP_formatColorOption
144
+ , escapeMarkup: function(m) {
145
+ return m;
146
+ }
147
+ });
148
+ }
149
+ if(jQuery('.irp-help').qtip) {
150
+ jQuery('.irp-help').qtip({
151
+ position: {
152
+ corner: {
153
+ target: 'topMiddle',
154
+ tooltip: 'bottomLeft'
155
+ }
156
+ },
157
+ show: {
158
+ when: {
159
+ event: 'mouseover'
160
+ }
161
+ },
162
+ hide: {
163
+ fixed: true,
164
+ when: {
165
+ event: 'mouseout'
166
+ }
167
+ },
168
+ style: {
169
+ tip: 'bottomLeft',
170
+ name: 'green'
171
+ }
172
+ });
173
+ }
174
+ });
assets/landing/img-whatsnew.001.jpg ADDED
Binary file
assets/landing/img-whatsnew.002.jpg ADDED
Binary file
assets/landing/img-whatsnew.003.jpg ADDED
Binary file
assets/landing/mac-irl-wahtsnew.png ADDED
Binary file
assets/templates/preview-button.jpg ADDED
Binary file
assets/templates/preview-kangoo.jpg ADDED
Binary file
assets/templates/preview-ruby.jpg ADDED
Binary file
assets/templates/styles.html ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #Template Minimalist
2
+ #Defaults {ctaTextColor=, postTitleColor=BLACK Dark, boxColor=WHITE Dark, borderColor=BLUE #2 Light, borderColorLabel=border}
3
+ <a href="{postHref}" target="{linkTarget}" {linkRel} class="{utemplate}">
4
+ {comment}
5
+ <style>
6
+ .{utemplate} {
7
+ padding:0px;
8
+ margin: 0;
9
+ padding-top:1em!important;
10
+ padding-bottom:1em!important;
11
+ width:100%;
12
+ display: block;
13
+ font-weight:bold;
14
+ background-color:{boxColor};
15
+ border:0!important;
16
+ {if borderColor}
17
+ border-left:4px solid {borderColor}!important;
18
+ {/if}
19
+ {if hasShadow}
20
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.17);
21
+ -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.17);
22
+ -o-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.17);
23
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.17);
24
+ {/if}
25
+ text-decoration:none;
26
+ }
27
+ .{utemplate}:active, .{utemplate}:hover {
28
+ opacity: 1;
29
+ transition: opacity 250ms;
30
+ webkit-transition: opacity 250ms;
31
+ text-decoration:none;
32
+ }
33
+ .{utemplate} {
34
+ transition: background-color 250ms;
35
+ webkit-transition: background-color 250ms;
36
+ opacity: {boxOpacity};
37
+ transition: opacity 250ms;
38
+ webkit-transition: opacity 250ms;
39
+ }
40
+ .{utemplate} .ctaText {
41
+ font-weight:bold;
42
+ color:{ctaTextColor};
43
+ text-decoration:none;
44
+ font-size: 16px;
45
+ }
46
+ .{utemplate} .postTitle {
47
+ color:{postTitleColor};
48
+ text-decoration: underline!important;
49
+ font-size: 16px;
50
+ }
51
+ .{utemplate}:hover .postTitle {
52
+ text-decoration: underline!important;
53
+ }
54
+ </style>
55
+ <div style="padding-left:1em; padding-right:1em;">
56
+ <span class="ctaText">{ctaText}</span>&nbsp;
57
+ <span class="postTitle">{postTitle}</span>
58
+ </div>
59
+ </a>
60
+
61
+ #Template Shock
62
+ #Defaults {ctaTextColor=GREY #1 Light, postTitleColor=BLUE #2 Dark, boxColor=ORANGE Light, borderColor=ORANGE Dark, borderColorLabel=hover}
63
+ <a href="{postHref}" target="{linkTarget}" {linkRel} class="{utemplate}">
64
+ {comment}
65
+ <style>
66
+ .{utemplate}
67
+ , .{utemplate} .postImageUrl
68
+ , .{utemplate} .centered-text-area {
69
+ min-height: 80px;
70
+ position: relative;
71
+ }
72
+ .{utemplate}
73
+ , .{utemplate}:hover
74
+ , .{utemplate}:visited
75
+ , .{utemplate}:active {
76
+ border:0!important;
77
+ }
78
+ .{utemplate} .clearfix:after {
79
+ content: "";
80
+ display: table;
81
+ clear: both;
82
+ }
83
+ .{utemplate} {
84
+ display: block;
85
+ transition: background-color 250ms;
86
+ webkit-transition: background-color 250ms;
87
+ width: 100%;
88
+ opacity: {boxOpacity};
89
+ transition: opacity 250ms;
90
+ webkit-transition: opacity 250ms;
91
+ background-color: {boxColor};
92
+ {if hasShadow}
93
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.17);
94
+ -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.17);
95
+ -o-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.17);
96
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.17);
97
+ {/if}
98
+ }
99
+ .{utemplate}:active
100
+ , .{utemplate}:hover {
101
+ opacity: 1;
102
+ transition: opacity 250ms;
103
+ webkit-transition: opacity 250ms;
104
+ background-color: {borderColor};
105
+ }
106
+ .{utemplate} .centered-text-area {
107
+ width: 100%;
108
+ position: relative;
109
+ }
110
+ .{utemplate} .ctaText {
111
+ border-bottom: 0 solid #fff;
112
+ color: {ctaTextColor};
113
+ font-size: 16px;
114
+ font-weight: bold;
115
+ margin: 0;
116
+ padding: 0;
117
+ text-decoration: underline;
118
+ }
119
+ .{utemplate} .postTitle {
120
+ color: {postTitleColor};
121
+ font-size: 16px;
122
+ font-weight: 600;
123
+ margin: 0;
124
+ padding: 0;
125
+ width: 100%;
126
+ }
127
+ .{utemplate} .ctaButton {
128
+ background-color: {boxColorHover}!important;
129
+ color: {ctaTextColor};
130
+ border: none;
131
+ border-radius: 3px;
132
+ box-shadow: none;
133
+ font-size: 14px;
134
+ font-weight: bold;
135
+ line-height: 26px;
136
+ moz-border-radius: 3px;
137
+ text-align: center;
138
+ text-decoration: none;
139
+ text-shadow: none;
140
+ width: 80px;
141
+ min-height: 80px;
142
+ background: url({assetsImages}simple-arrow.png)no-repeat;
143
+ position: absolute;
144
+ right: 0;
145
+ top: 0;
146
+ }
147
+ .{utemplate}:hover .ctaButton {
148
+ background-color: {borderColorHover}!important;
149
+ }
150
+ .{utemplate} .centered-text {
151
+ display: table;
152
+ height: 80px;
153
+ padding-left: 18px;
154
+ top: 0;
155
+ }
156
+ .{utemplate} .{utemplate}-content {
157
+ display: table-cell;
158
+ margin: 0;
159
+ padding: 0;
160
+ padding-right: 108px;
161
+ position: relative;
162
+ vertical-align: middle;
163
+ width: 100%;
164
+ }
165
+ .{utemplate}:after {
166
+ content: "";
167
+ display: block;
168
+ clear: both;
169
+ }
170
+ </style>
171
+ <div class="centered-text-area">
172
+ <div class="centered-text" style="float: left;">
173
+ <div class="{utemplate}-content">
174
+ <span class="ctaText">{ctaText}</span>&nbsp;
175
+ <span class="postTitle">{postTitle}</span>
176
+ </div>
177
+ </div>
178
+ </div>
179
+ <div class="ctaButton"></div>
180
+ </a>
181
+
182
+ #Template Ruby
183
+ #Defaults {proTheme=true, ctaTextColor=BLUE #1 Light, postTitleColor=GREY #1 Light, boxColor=BLUE #2 Dark, borderColor=, borderColorLabel=arrow}
184
+ <a href="{demoLink}" target="_blank" rel="nofollow" class="{utemplate}">
185
+ <img src="{assets}templates/preview-ruby.jpg" />
186
+ </a>
187
+
188
+ #Template Button
189
+ #Defaults {proTheme=true, ctaTextColor=WHITE Light, postTitleColor=GREY #1 Light, boxColor=BLACK Light, borderColor=AQUA Light, borderColorLabel=button}
190
+ <a href="{demoLink}" target="_blank" rel="nofollow" class="{utemplate}">
191
+ <img src="{assets}templates/preview-button.jpg" />
192
+ </a>
193
+
194
+ #Template Kangoo
195
+ #Defaults {proTheme=true, ctaTextColor=BLUE #2 Light, postTitleColor=BLACK Dark, boxColor=WHITE Dark, borderColor=WHITE Light, borderColorLabel=hover}
196
+ <a href="{demoLink}" target="_blank" rel="nofollow" class="{utemplate}">
197
+ <img src="{assets}templates/preview-kangoo.jpg" />
198
+ </a>
autoload.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ spl_autoload_register('irp_autoload');
3
+ function irp_autoload($class) {
4
+ $root=dirname(__FILE__).'/includes/classes/';
5
+ irp_autoload_root($root, $class);
6
+ }
7
+ function irp_autoload_root($root, $class) {
8
+ $slash=substr($root, strlen($root)-1);
9
+ if($slash!='/' && $slash!='\\') {
10
+ $root.='/';
11
+ }
12
+ $name=str_replace(IRP_PLUGIN_PREFIX, '', $class);
13
+ if(strpos($class, IRP_PLUGIN_PREFIX)===FALSE) {
14
+ //autoload only plugin classes
15
+ return;
16
+ }
17
+
18
+ $h=opendir($root);
19
+ while($file=readdir($h)) {
20
+ if(is_dir($root.$file) && $file != '.' && $file != '..') {
21
+ irp_autoload_root($root.$file, $class);
22
+ } elseif(file_exists($root.$name.'.php')) {
23
+ include_once($root.$name.'.php');
24
+ } elseif(file_exists($root.$class.'.php')) {
25
+ include_once($root.$class.'.php');
26
+ }
27
+ }
28
+ }
29
+ function irp_include_php($root) {
30
+ $h=opendir($root);
31
+ $slash=substr($root, strlen($root)-1);
32
+ if($slash!='/' && $slash!='\\') {
33
+ $root.='/';
34
+ }
35
+
36
+ while($file=readdir($h)) {
37
+ if(is_dir($root.$file) && $file != '.' && $file != '..'){
38
+ irp_include_php($root.$file);
39
+ } elseif(strlen($file)>5) {
40
+ $ext='.php';
41
+ $length=strlen($ext);
42
+ $start=$length*-1; //negative
43
+ if(strcasecmp(substr($file, $start), $ext)==0) {
44
+ include_once($root.$file);
45
+ }
46
+ }
47
+ }
48
+ }
includes/actions.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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', 'irp_do_action');
24
+ add_action('wp_ajax_do_action', 'irp_do_action');
25
+ function irp_do_action() {
26
+ global $irp;
27
+
28
+ if ($irp->Utils->qs('irp_action')) {
29
+ $args=array_merge($_GET, $_POST, $_COOKIE, $_SERVER);
30
+ $name='irp_'.$irp->Utils->qs('irp_action');
31
+ if(has_action($name)) {
32
+ $irp->Log->debug('EXECUTING ACTION=%s', $name);
33
+ do_action($name, $args);
34
+ } elseif(function_exists($name)) {
35
+ $irp->Log->debug('EXECUTING FUNCTION=%s DATA=%s', $name, $args);
36
+ call_user_func($name, $args);
37
+ } elseif(strpos($irp->Utils->qs('irp_action'), '_')!==FALSE) {
38
+ $pos=strpos($irp->Utils->qs('irp_action'), '_');
39
+ $what=substr($irp->Utils->qs('irp_action'), 0, $pos);
40
+ $function=substr($irp->Utils->qs('irp_action'), $pos+1);
41
+
42
+ $class=NULL;
43
+ switch (strtolower($what)) {
44
+ case 'cron':
45
+ $class=$irp->Cron;
46
+ break;
47
+ case 'tracking':
48
+ $class=$irp->Tracking;
49
+ break;
50
+ case 'properties':
51
+ $class=$irp->Options;
52
+ break;
53
+ }
54
+
55
+ if(!$class) {
56
+ $irp->Log->fatal('NO CLASS FOR=%s IN ACTION=%s', $what, $irp->Utils->qs('irp_action'));
57
+ } elseif(!method_exists ($class, $function)) {
58
+ $irp->Log->fatal('NO METHOD FOR=%s IN CLASS=%s IN ACTION=%s', $function, $what, $irp->Utils->qs('irp_action'));
59
+ } else {
60
+ $irp->Log->debug('METHOD=%s OF CLASS=%s', $function, $what);
61
+ call_user_func(array($class, $function), $args);
62
+ }
63
+ } else {
64
+ $irp->Log->fatal('NO FUNCTION FOR==%s', $irp->Utils->qs('irp_action'));
65
+ }
66
+ }
67
+ }
includes/admin/about.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ function irp_ui_about() {
3
+ global $irp;
4
+ irp_ui_tracking(TRUE);
5
+ ?>
6
+ <div><?php $irp->Lang->P('AboutText')?></div>
7
+ <style>
8
+ ul li {
9
+ padding:2px;
10
+ }
11
+ </style>
12
+ <ul>
13
+ <li>
14
+ <img style="float:left; margin-right:10px;" src="<?php echo IRP_PLUGIN_IMAGES?>email.png" />
15
+ <a href="mailto:aleste@intellywp.com">aleste@intellywp.com</a>
16
+ </li>
17
+ <li>
18
+ <img style="float:left; margin-right:10px;" src="<?php echo IRP_PLUGIN_IMAGES?>twitter.png" />
19
+ <?php $irp->Utils->twitter('intellywp')?>
20
+ </li>
21
+ <li>
22
+ <img style="float:left; margin-right:10px;" src="<?php echo IRP_PLUGIN_IMAGES?>internet.png" />
23
+ <a href="http://www.intellywp.com" target="_new">IntellyWP.com</a>
24
+ </li>
25
+ </ul>
26
+ <?php
27
+ }
includes/admin/button-mce.php ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ add_action('admin_head', 'irp_add_mce_button');
3
+ function irp_add_mce_button() {
4
+ global $typenow;
5
+
6
+ if (!current_user_can('edit_posts') && !current_user_can('edit_pages')) {
7
+ return;
8
+ }
9
+
10
+ if(!in_array($typenow, array('post', 'page'))) {
11
+ return;
12
+ }
13
+ if (get_user_option('rich_editing') == 'true') {
14
+ add_filter("mce_external_plugins", "irp_add_mce_plugin");
15
+ add_filter('mce_buttons', 'irp_register_mce_button');
16
+ }
17
+ }
18
+
19
+ function irp_add_mce_plugin($plugin_array) {
20
+ $plugin_array['irp_mce_button']=IRP_PLUGIN_ASSETS.'js/button-mce.js';
21
+ return $plugin_array;
22
+ }
23
+ function irp_register_mce_button($buttons) {
24
+ array_push($buttons, "irp_mce_button");
25
+ return $buttons;
26
+ }
27
+
28
+ function irp_ui_button_editor() {
29
+ global $irp;
30
+
31
+ $irp->Utils->printScriptCss();
32
+ $irp->Form->prefix='Editor';
33
+ $irp->Form->labels=FALSE;
34
+
35
+ $args=array('class'=>'wp-admin wp-core-ui admin-bar'
36
+ , 'style'=>'padding:10px; margin-left:auto; margin-right:auto;');
37
+ $irp->Form->formStarts('post', '', $args);
38
+ {
39
+ ?>
40
+ <p style="text-align:center;"><?php $irp->Lang->P('EditorSubtitle') ?></p>
41
+ <?php
42
+ $args = array('post_type' => 'post', 'all' => FALSE);
43
+ $options = $irp->Utils->query(IRP_QUERY_POSTS_OF_TYPE, $args);
44
+ $irp->Form->text('irpPostId', '', FALSE);
45
+ ?>
46
+ <div style="clear:both;"></div>
47
+ <p style="text-align:right;">
48
+ <input type="button" id="btnInsert" class="button button-primary irp-button irp-submit" value="<?php $irp->Lang->P('Insert')?>"/>
49
+ <input type="button" id="btnClose" class="button irp-button" value="<?php $irp->Lang->P('Cancel')?>"/>
50
+ </p>
51
+
52
+ <script>
53
+ jQuery(function () {
54
+ jQuery('#btnInsert').click(function () {
55
+ var editor = top.tinymce.activeEditor;
56
+ var postId = parseInt(jQuery('#irpPostId').val());
57
+ var name=jQuery('#select2-chosen-1').text().replace('"', ' ');
58
+ if(name) {
59
+ name='name="'+name+'"';
60
+ }
61
+ if (postId > 0) {
62
+ var code = '[irp posts="' + postId + '" '+name+']';
63
+ editor.insertContent(code);
64
+ }
65
+ editor.windowManager.close();
66
+ });
67
+ jQuery('#btnClose').click(function () {
68
+ var editor = top.tinymce.activeEditor;
69
+ editor.windowManager.close();
70
+ });
71
+ /*
72
+ jQuery("#irpPostId").select2({
73
+ placeholder: "Type here..."
74
+ , theme: "classic"
75
+ , width: '100%'
76
+ //, maximumSelectionLength: 3
77
+ });
78
+ */
79
+ var ajaxurl = 'admin-ajax.php';
80
+ jQuery('#irpPostId').select2({
81
+
82
+ ajax: {
83
+
84
+ url: ajaxurl,
85
+ dataType: 'json',
86
+
87
+ delay: 250,
88
+
89
+ data: function (term, page) {
90
+
91
+ return {
92
+ action: 'irp_list_posts',
93
+ irp_post_type: '<?php echo esc_attr($_REQUEST['irp_post_type']);?>',
94
+ q: term,
95
+ page: page
96
+ };
97
+
98
+ },
99
+
100
+ results: function (data, page) {
101
+
102
+ page = page || 1;
103
+
104
+ return {
105
+ results: data.items,
106
+ more: false,
107
+ };
108
+
109
+ },
110
+
111
+ cache: true
112
+
113
+ },
114
+
115
+ placeholder: "Type here to search an item...",
116
+ minimumInputLength: 3,
117
+ width: '100%'
118
+
119
+ });
120
+ });
121
+ </script>
122
+
123
+ <style>
124
+ .select2-results {
125
+ max-height: 100px;
126
+ overflow-y: auto;
127
+ }
128
+ </style>
129
+ <?php
130
+ }
131
+ $irp->Form->formEnds();
132
+ exit;
133
+ }
134
+
includes/admin/faq.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ function irp_ui_faq() {
3
+ global $irp;
4
+ $i=1;
5
+ while($irp->Lang->H('Faq.Question'.$i)) {
6
+ $q=$irp->Lang->L('Faq.Question'.$i);
7
+ $r=$irp->Lang->L('Faq.Response'.$i);
8
+ ?>
9
+ <p>
10
+ <b><?php echo $q?></b>
11
+ <br/>
12
+ <?php echo $r?>
13
+ </p>
14
+ <?php
15
+ ++$i;
16
+ }
17
+ }
includes/admin/feedback.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ function irp_ui_feedback() {
4
+ global $irp;
5
+
6
+ $irp->Form->prefix='Feedback';
7
+ if($irp->Check->nonce('irp_feedback', 'irp_feedback')) {
8
+ $irp->Check->email('email');
9
+ $irp->Check->value('body');
10
+
11
+ if(!$irp->Check->hasErrors()) {
12
+ $irp->Options->setFeedbackEmail($irp->Check->of('email'));
13
+ $id=-1;
14
+ if($irp->Check->of('track', 0)) {
15
+ $id=$irp->Tracking->sendTracking(TRUE);
16
+ }
17
+ $irp->Check->data['tracking_id']=$id;
18
+ $irp->Check->data['plugin']=IRP_PLUGIN_SLUG;
19
+ $data=$irp->Utils->remotePost('feedback', $irp->Check->data);
20
+ if($data) {
21
+ $irp->Options->pushSuccessMessage('FeedbackSuccess');
22
+ } else {
23
+ $irp->Options->pushErrorMessage('FeedbackError');
24
+ }
25
+ }
26
+ }
27
+ ?>
28
+ <br>
29
+ <h2><?php $irp->Lang->P('FeedbackHeader')?></h2>
30
+ <?php
31
+ $irp->Options->writeMessages();
32
+
33
+ $irp->Form->formStarts();
34
+ $irp->Form->text('email', $irp->Options->getFeedbackEmail());
35
+ $irp->Form->textarea('body', '', array('rows'=>5));
36
+
37
+ $irp->Form->leftLabels=FALSE;
38
+ $irp->Form->checkbox('track');
39
+ $irp->Form->leftLabels=TRUE;
40
+
41
+ $irp->Form->nonce('irp_feedback', 'irp_feedback');
42
+ $irp->Form->submit('Send');
43
+ $irp->Form->formEnds();
44
+ }
includes/admin/metabox.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ function irp_ui_metabox($post) {
3
+ global $irp;
4
+
5
+ wp_nonce_field('irp_meta_box', 'irp_meta_box_nonce');
6
+ $array=$irp->Options->getExcludedPostsIds();
7
+ $exclude=FALSE;
8
+ if(in_array($post->ID, $array)) {
9
+ $exclude=TRUE;
10
+ }
11
+ ?>
12
+ <input type="hidden" name="irp_previous" value="<?php echo ($exclude ? 1 : 0)?>" />
13
+ <input type="checkbox" class="irp-checkbox" name="irp_exclude" value="1" <?php echo ($exclude ? ' CHECKED' : '')?> />
14
+ <?php $irp->Lang->P('Post without related posts')?>
15
+ <?php
16
+ }
17
+
18
+ add_action('add_meta_boxes', 'irp_add_meta_box');
19
+ function irp_add_meta_box() {
20
+ global $irp;
21
+
22
+ if($irp->Plugin->isActive(IRP_PLUGINS_INTELLY_RELATED_POSTS_PRO)) {
23
+ return;
24
+ }
25
+
26
+ $options=$irp->Options->getMetaboxPostTypes();
27
+ $screens=array();
28
+ foreach($options as $k=>$v) {
29
+ if(intval($v)>0) {
30
+ $screens[]=$k;
31
+ }
32
+ }
33
+ if(count($screens)>0) {
34
+ foreach ($screens as $screen) {
35
+ add_meta_box(
36
+ 'irp_sectionid'
37
+ , $irp->Lang->L('Related Posts by IntellyWP')
38
+ , 'irp_ui_metabox'
39
+ , $screen
40
+ , 'side'
41
+ );
42
+ }
43
+ }
44
+ }
45
+ //si aggancia a quando un post viene salvato per salvare anche gli altri dati del metabox
46
+ add_action('save_post', 'irp_save_meta_box_data');
47
+ function irp_save_meta_box_data($postId) {
48
+ global $irp;
49
+
50
+ if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
51
+ return;
52
+ }
53
+ if (!isset($_POST['irp_meta_box_nonce']) || !isset($_POST['post_type'])) {
54
+ return;
55
+ }
56
+ if (!wp_verify_nonce( $_POST['irp_meta_box_nonce'], 'irp_meta_box')) {
57
+ return;
58
+ }
59
+
60
+ $exclude=$irp->Utils->qs('irp_exclude', 0);
61
+ $previous=$irp->Utils->qs('irp_previous', 0);
62
+ if($exclude!=$previous) {
63
+ $array=$irp->Options->getExcludedPostsIds();
64
+ $array=array_diff($array, array($postId));
65
+ if($exclude) {
66
+ array_push($array, $postId);
67
+ }
68
+ $irp->Options->setExcludedPostsIds($array);
69
+ }
70
+ }
includes/admin/settings.php ADDED
@@ -0,0 +1,417 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ function irp_ui_tracking($override=FALSE) {
3
+ global $irp;
4
+
5
+ $track=$irp->Utils->qs('track', '');
6
+ if($track!='') {
7
+ $track=intval($track);
8
+ $irp->Options->setTrackingEnable($track);
9
+ $irp->Tracking->sendTracking(TRUE);
10
+ }
11
+
12
+ $uri=IRP_TAB_SETTINGS_URI.'&track=';
13
+ if($irp->Options->isTrackingEnable()) {
14
+ if($override) {
15
+ $uri.='0';
16
+ $irp->Options->pushSuccessMessage('EnableAllowTrackingNotice', $uri);
17
+ }
18
+ } else {
19
+ $uri.='1';
20
+ $irp->Options->pushWarningMessage('DisableAllowTrackingNotice', $uri);
21
+ }
22
+ $irp->Options->writeMessages();
23
+ }
24
+ function irp_io_first_time() {
25
+ global $irp;
26
+ if($irp->Options->isShowActivationNotice()) {
27
+ $irp->Options->pushSuccessMessage('FirstTimeActivation');
28
+ $irp->Options->writeMessages();
29
+ $irp->Options->setShowActivationNotice(FALSE);
30
+ }
31
+ }
32
+ function irp_ui_box_preview() {
33
+ global $irp;
34
+
35
+ $count=$irp->Options->getRewritePostsInBoxCount();
36
+ $count=$irp->Utils->iqs('rewritePostsInBoxCount', $count);
37
+ $args=array(
38
+ 'orderby'=>'rand'
39
+ , 'numberposts'=>$count
40
+ );
41
+
42
+ $days=$irp->Options->getRewritePostsDays();
43
+ $days=$irp->Utils->iqs('rewritePostsDays', $days);
44
+ if($days>0) {
45
+ $args['date_query'] = array(
46
+ 'column' => 'post_date'
47
+ , 'after' => '- '.$days.' days'
48
+ );
49
+ }
50
+ $posts=get_posts($args);
51
+ $ids=array();
52
+ foreach($posts as $p) {
53
+ $ids[]=$p->ID;
54
+ }
55
+ if(count($ids)==0) {
56
+ echo "<b>No posts available. Check settings and try again</b>";
57
+ die();
58
+ }
59
+
60
+ $defaults=$irp->Options->getTemplateStyle();
61
+ $args=$irp->Utils->aqs('template-', $defaults);
62
+ $args['includeCss']=TRUE;
63
+ $args['preview']=TRUE;
64
+ $box=irp_ui_get_box($ids, $args);
65
+ echo $box;
66
+ die();
67
+ }
68
+ function irp_ui_settings() {
69
+ global $irp;
70
+ irp_ui_tracking(FALSE);
71
+
72
+ ?>
73
+ <script>
74
+ var IRP_preview=true;
75
+ var IRP_labelColor='';
76
+ var IRP_defaults={};
77
+ <?php
78
+ $defaults=$irp->HtmlTemplate->getDefaults();
79
+ foreach($defaults as $k=>$v) {
80
+ $buffer='';
81
+ foreach($v as $kk=>$vv) {
82
+ if($buffer!='') {
83
+ $buffer.=', ';
84
+ }
85
+
86
+ if(stripos($kk, 'label')!==FALSE) {
87
+ $vv=$irp->Lang->L('Settings.Color.'.$vv);
88
+ } elseif(stripos($kk, 'color')!==FALSE) {
89
+ $vv=$irp->Options->getColor($vv);
90
+ }
91
+
92
+ $buffer.=$kk.': "'.$vv.'"';
93
+ }
94
+ ?>
95
+ IRP_defaults["<?php echo $k?>"]={<?php echo $buffer?>};
96
+ <?php }
97
+ ?>
98
+
99
+ function IRP_changeTheme() {
100
+ IRP_preview=false;
101
+ t=IRP_val('template-template');
102
+ t=IRP_defaults[t];
103
+ isProTheme=false;
104
+ console.log(t);
105
+ jQuery.each(t, function(k,v) {
106
+ if(IRP_stripos(k, 'color')!==false) {
107
+ var $k=jQuery('[name=template-'+k+']');
108
+ $k.select2("val", v);
109
+ } else if(k=='proTheme') {
110
+ isProTheme=(v+''.toLowerCase()=='true');
111
+ }
112
+ });
113
+
114
+ jQuery("[name*='Color']").each(function(i,v) {
115
+ var $cbo=jQuery(this);
116
+ $cbo.prop("disabled", isProTheme);
117
+ $cbo.select2("enable", !isProTheme);
118
+ });
119
+ jQuery("[id*='ColorLabel']").each(function(i,v) {
120
+ var $lbl=jQuery(this);
121
+ if(IRP_labelColor!='') {
122
+ IRP_labelColor=$lbl.css('color');
123
+ }
124
+ if(isProTheme) {
125
+ $lbl.css('color', '#ccc');
126
+ } else {
127
+ $lbl.css('color', IRP_labelColor);
128
+ }
129
+ });
130
+ jQuery('.irp-submit').prop("disabled", isProTheme);
131
+ IRP_preview=true;
132
+ }
133
+ function IRP_changeRelatedBox() {
134
+ if(!IRP_preview) {
135
+ return;
136
+ }
137
+
138
+ var t=IRP_val('template-template');
139
+ t=IRP_defaults[t].borderColorLabel;
140
+ jQuery('#template-borderColorLabel').text(t);
141
+
142
+ data=IRP_aval('template-');
143
+ data=jQuery.extend({
144
+ 'action': 'do_action'
145
+ , 'irp_action': 'ui_box_preview'
146
+ , 'rewritePostsDays': IRP_val('irpRewritePostsDays')
147
+ }, data);
148
+ //console.log(data);
149
+
150
+ var request=jQuery.ajax({
151
+ url: ajaxurl
152
+ , method: "POST"
153
+ , data: data
154
+ , dataType: "html"
155
+ });
156
+
157
+ request.done(function(html) {
158
+ jQuery("#relatedBoxExample").html(html);
159
+ });
160
+ }
161
+
162
+ jQuery(function() {
163
+ IRP_preview=false;
164
+ var array=['irpRewritePostsDays', 'irpRewritePostsInBoxCount', 'irpRewriteBoxesCount'];
165
+ for(i=0; i<array.length; i++) {
166
+ if(jQuery('[name='+array[i]+']').length>0) {
167
+ jQuery('[name='+array[i]+']').change(function() {
168
+ IRP_changeRelatedBox();
169
+ });
170
+ }
171
+ }
172
+ jQuery("[name^='template-']").change(function() {
173
+ if(!IRP_preview) {
174
+ return;
175
+ }
176
+
177
+ var $self=jQuery(this);
178
+ var name=$self.attr('name');
179
+ if(name=='template-template') {
180
+ IRP_changeTheme();
181
+ }
182
+ IRP_changeRelatedBox();
183
+ });
184
+ //IRP_changeTheme();
185
+ IRP_preview=true;
186
+ IRP_changeRelatedBox();
187
+ });
188
+ </script>
189
+ <?php
190
+
191
+ $irp->Form->prefix='Settings';
192
+ $irp->Form->helps = FALSE;
193
+ $irp->Form->formStarts();
194
+
195
+ if($irp->Check->nonce('irp_settings')) {
196
+
197
+ $irp->Options->resetMaxExecutionTime();
198
+ $irp->Options->setActive($irp->Utils->iqs('irpActive'));
199
+
200
+ $defaults=array(
201
+ 'hasShadow'=>0
202
+ , 'hasPoweredBy'=>0
203
+ );
204
+ $template=$irp->Utils->aqs('template-', $defaults);
205
+ $irp->Options->setTemplateStyle($template);
206
+
207
+ $irp->Options->setMarginTop($irp->Utils->qs('marginTop', '0em'));
208
+ $irp->Options->setMarginBottom($irp->Utils->qs('marginBottom', '1em'));
209
+ $irp->Options->setRewriteActive($irp->Utils->iqs('irpRewriteActive'));
210
+ $irp->Options->setRewriteBoxesCount($irp->Utils->iqs('irpRewriteBoxesCount', 1));
211
+ //$irp->Options->setRewritePostsInBoxCount($irp->Utils->iqs('irpRewritePostsInBoxCount', 1));
212
+ $irp->Options->setRewritePostsDays($irp->Utils->iqs('irpRewritePostsDays', 0));
213
+ $irp->Options->setRewriteThreshold($irp->Utils->iqs('irpRewriteThreshold', 300));
214
+ $irp->Options->setRewriteAtEnd($irp->Utils->iqs('irpRewriteAtEnd'));
215
+
216
+ $irp->Options->setEngineSearch($irp->Utils->iqs('irpEngineSearch', IRP_ENGINE_SEARCH_CATEGORIES_TAGS));
217
+
218
+ $options = $irp->Options->getRewritePostTypes();
219
+ foreach ($options as $k => $template) {
220
+ $template = intval($irp->Utils->qs('irpRewritePostType_' . $k, 0));
221
+ $options[$k] = $template;
222
+ }
223
+ $irp->Options->setRewritePostTypes($options);
224
+
225
+ $options = $irp->Options->getMetaboxPostTypes();
226
+ foreach ($options as $k => $template) {
227
+ $template = intval($irp->Utils->qs('metabox_' . $k, 0));
228
+ $options[$k] = $template;
229
+ }
230
+ $irp->Options->setMetaboxPostTypes($options);
231
+ }
232
+
233
+ $c=wp_count_posts()->publish;
234
+ $t=$irp->Options->getMaxExecutionTime();
235
+ if($t>0) {?>
236
+ <p style="width:auto; font-style: italic;"><?php $irp->Lang->P('PreviewSectionMaxTime', $t, $c)?></p>
237
+ <?php }
238
+
239
+ $irp->Form->p('GeneralSection');
240
+ $args=array(
241
+ 'class'=>'irp-hideShow irp-checkbox'
242
+ , 'irp-hideIfTrue'=>'false'
243
+ , 'irp-hideShow'=>'irp-active-box'
244
+ );
245
+ $irp->Form->checkbox('irpActive', $irp->Options->isActive(), 1, $args);
246
+ $args=array(
247
+ 'id'=>'irp-active-box'
248
+ , 'name'=>'irp-active-box'
249
+ , 'style'=>'margin-top:10px;'
250
+ );
251
+ $irp->Form->divStarts($args);
252
+ {
253
+ $template=$irp->Options->getTemplateStyle();
254
+ $prefix='template-';
255
+ $irp->Form->text($prefix.'ctaText', $irp->Utils->get($template, 'ctaText'));
256
+ $options=$irp->HtmlTemplate->getTemplatesNames();
257
+ $irp->Form->select($prefix.'template', $irp->Utils->get($template, 'template'), $options);
258
+ $irp->Form->number($prefix.'boxOpacity', $irp->Utils->get($template, 'boxOpacity'));
259
+ $irp->Form->text('marginTop', $irp->Options->getMarginTop());
260
+ $irp->Form->text('marginBottom', $irp->Options->getMarginBottom());
261
+ //$options=array('none', 'capitalize', 'uppercase', 'lowercase');
262
+ //$irp->Form->select($t.'textTransform', $irp->Utils->get($v, 'textTransform'), $options);
263
+ $array=array('ctaTextColor', 'postTitleColor', 'boxColor', 'borderColor');
264
+ $blanks=array('(Default)', '(Default)', '(Trasparent)', '(Without)');
265
+ for($i=0; $i<count($array); $i++) {
266
+ $k=$array[$i];
267
+ $v=$blanks[$i];
268
+ $colors=$irp->Options->getColors($v);
269
+
270
+ $v=$irp->Utils->get($template, $k);
271
+ $v=$irp->Options->getColor($v);
272
+ $irp->Form->colorSelect($prefix.$k, $v, $colors);
273
+ }
274
+ $array=array('hasShadow', 'hasPoweredBy');
275
+ foreach($array as $k) {
276
+ $irp->Form->checkbox($prefix.$k, $irp->Utils->iget($template, $k));
277
+ }
278
+ ?>
279
+ <div style="padding-left:10px; padding-right:10px; border:1px dashed #444444">
280
+ <?php $irp->Form->p('PreviewSection'); ?>
281
+ <p id="relatedBoxExample" style="width:auto;"></p>
282
+ </div>
283
+ <?php
284
+ $irp->Form->p('RewriteSection');
285
+ $args=array(
286
+ 'class'=>'irp-hideShow irp-checkbox'
287
+ , 'irp-hideIfTrue'=>'false'
288
+ , 'irp-hideShow'=>'irp-rewrite-box'
289
+ );
290
+ $irp->Form->checkbox('irpRewriteActive', $irp->Options->isRewriteActive(), 1, $args);
291
+ $args=array('id'=>'irp-rewrite-box', 'name'=>'irp-rewrite-box', 'style'=>'margin-top:10px;');
292
+ $irp->Form->divStarts($args);
293
+ {
294
+ $options=array();
295
+ $options[]=array('id'=>1, 'name'=>1);
296
+ $options[]=array('id'=>2, 'name'=>2);
297
+ $options[]=array('id'=>3, 'name'=>3);
298
+ $irp->Form->select('irpRewriteBoxesCount', $irp->Options->getRewriteBoxesCount(), $options);
299
+ $irp->Form->number('irpRewritePostsDays', $irp->Options->getRewritePostsDays());
300
+ $irp->Form->number('irpRewriteThreshold', $irp->Options->getRewriteThreshold(), $args);
301
+ $irp->Form->checkbox('irpRewriteAtEnd', $irp->Options->isRewriteAtEnd());
302
+ $irp->Form->p('');
303
+
304
+ $options=$irp->Options->getRewritePostTypes();
305
+ $types=$irp->Utils->query(IRP_QUERY_POST_TYPES);
306
+ foreach($types as $v) {
307
+ $v=$v['name'];
308
+ $irp->Form->checkbox('irpRewritePostType_'.$v, $options[$v]);
309
+ }
310
+ }
311
+ $irp->Form->divEnds();
312
+
313
+ $irp->Form->p('EngineSection');
314
+ $irp->Form->divStarts();
315
+ {
316
+ $options=array(
317
+ IRP_ENGINE_SEARCH_CATEGORIES_TAGS
318
+ , IRP_ENGINE_SEARCH_CATEGORIES
319
+ , IRP_ENGINE_SEARCH_TAGS
320
+ );
321
+ $irp->Form->select('irpEngineSearch', $irp->Options->getEngineSearch(), $options);
322
+ $options=array();
323
+ $options[]=array('id'=>'nofollow', 'name'=>'nofollow');
324
+ $options[]=array('id'=>'dofollow', 'name'=>'dofollow');
325
+ $k='linkRel';
326
+
327
+ $irp->Form->select($prefix.$k, $irp->Utils->get($template, $k), $options);
328
+ $options=array();
329
+ $options[]=array('id'=>'_blank', 'name'=>'_blank');
330
+ $options[]=array('id'=>'_self', 'name'=>'_self');
331
+ $k='linkTarget';
332
+ $irp->Form->select($prefix.$k, $irp->Utils->get($template, $k), $options);
333
+ }
334
+ $irp->Form->divEnds();
335
+
336
+ $irp->Form->p('MetaboxSection');
337
+ $irp->Form->divStarts();
338
+ {
339
+ $metaboxes=$irp->Options->getMetaboxPostTypes();
340
+ $types=$irp->Utils->query(IRP_QUERY_POST_TYPES);
341
+ foreach($types as $template) {
342
+ $template=$template['name'];
343
+ $irp->Form->checkbox('metabox_'.$template, $metaboxes[$template]);
344
+ }
345
+ }
346
+ $irp->Form->divEnds();
347
+ }
348
+ $irp->Form->divEnds();
349
+
350
+ $irp->Form->nonce('irp_settings');
351
+ irp_notice_pro_features();
352
+ $args=array('id'=>'boxDontSave', 'style'=>'display:none;');
353
+ $irp->Form->divStarts($args);
354
+ {
355
+ $irp->Form->p('Notice.DontSave');
356
+ }
357
+ $irp->Form->divEnds();
358
+ $irp->Form->submit('Save');
359
+
360
+ $irp->Form->formEnds();
361
+ $irp->Form->helps=FALSE;
362
+ }
363
+
364
+ function irp_notice_pro_features() {
365
+ global $irp;
366
+
367
+ ?>
368
+ <br/>
369
+ <div class="message updated below-h2" style="max-width:600px;">
370
+ <div style="height:10px;"></div>
371
+ <?php
372
+ $i=1;
373
+ while($irp->Lang->H('Notice.ProHeader'.$i)) {
374
+ $irp->Lang->P('Notice.ProHeader'.$i);
375
+ echo '<br/>';
376
+ ++$i;
377
+ }
378
+ $i=1;
379
+ ?>
380
+ <br/>
381
+ <?php
382
+ /*
383
+ $options = array('public' => TRUE, '_builtin' => FALSE);
384
+ $q=get_post_types($options, 'names');
385
+ if(is_array($q) && count($q)>0) {
386
+ sort($q);
387
+ $q=implode(', ', $q);
388
+ $q='(<b>'.$q.'</b>)';
389
+ } else {
390
+ $q='';
391
+ }*/
392
+
393
+ while($irp->Lang->H('Notice.ProFeature'.$i)) { ?>
394
+ <div style="clear:both; margin-top: 2px;"></div>
395
+ <div style="float:left; vertical-align:middle; height:24px; margin-right:5px;">
396
+ <img src="<?php echo IRP_PLUGIN_IMAGES?>tick.png" />
397
+ </div>
398
+ <div style="float:left; vertical-align:middle; height:24px;">
399
+ <?php $irp->Lang->P('Notice.ProFeature'.$i)?>
400
+ </div>
401
+ <?php ++$i;
402
+ }
403
+ ?>
404
+ <div style="clear:both;"></div>
405
+ <div style="height:10px;"></div>
406
+ <div style="float:right;">
407
+ <?php
408
+ $url=IRP_INTELLYWP_SITE.IRP_PLUGIN_SLUG.'/?utm_source=free-users&utm_medium=irp-cta&utm_campaign=IRP';
409
+ ?>
410
+ <a href="<?php echo $url?>" target="_blank">
411
+ <b><?php $irp->Lang->P('Notice.ProCTA')?></b>
412
+ </a>
413
+ </div>
414
+ <div style="height:10px; clear:both;"></div>
415
+ </div>
416
+ <br/>
417
+ <?php }
includes/admin/whatsnew.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ function irp_ui_whats_new() {
3
+ ?>
4
+ <style>
5
+ .irp-grid {
6
+ margin-left: auto;
7
+ margin-right: auto;
8
+ border-spacing: 10px;
9
+ }
10
+ .irp-grid td {
11
+ text-align: center;
12
+ }
13
+ .irp-headline {
14
+ font-size:40px;
15
+ font-weight:bold;
16
+ text-align:center;
17
+ margin: 5px!important;
18
+ }
19
+ </style>
20
+
21
+ <p class="irp-headline">Welcome in Inline Related Posts (v.<?php echo IRP_PLUGIN_VERSION ?>)</p>
22
+ <p class="irp-headline" style="font-size: 35px;">Get even more page views with box themes</p>
23
+ <div style="clear:both; height:30px;"></div>
24
+
25
+ <div style="text-align:center; width:auto;">
26
+ <img src="<?php echo IRP_PLUGIN_ASSETS ?>landing/mac-irl-wahtsnew.png" />
27
+ </div>
28
+ <div style="clear:both; height:30px;"></div>
29
+
30
+ <table border="0" class="irp-grid">
31
+ <tr>
32
+ <td><img src="<?php echo IRP_PLUGIN_ASSETS ?>landing/img-whatsnew.001.jpg" /></td>
33
+ <td><img src="<?php echo IRP_PLUGIN_ASSETS ?>landing/img-whatsnew.002.jpg" /></td>
34
+ <td><img src="<?php echo IRP_PLUGIN_ASSETS ?>landing/img-whatsnew.003.jpg" /></td>
35
+ </tr>
36
+ <tr>
37
+ <td>Box Themes</td>
38
+ <td>More colors</td>
39
+ <td>Featured Image</td>
40
+ </tr>
41
+ </table>
42
+ <div style="clear:both"></div>
43
+
44
+ <hr/>
45
+
46
+ <p class="irp-headline">Get gorgeous themes with Inline Related Posts PRO</p>
47
+ <table border="0" class="irp-grid">
48
+ <tr>
49
+ <td style="text-align:left;">
50
+ <?php irp_notice_pro_features() ?>
51
+ </td>
52
+ <td>
53
+ <div style="border:1px dashed red; padding:10px;">
54
+ <iframe width="560" height="350" src="https://www.youtube.com/embed/CjdTr14Nd1g" frameborder="0" allowfullscreen></iframe>
55
+ </div>
56
+ </td>
57
+ </tr>
58
+ </table>
59
+
60
+ <table border="0" class="irp-grid">
61
+ <tr>
62
+ <td style="text-align: right; vertical-align: top;">
63
+ <form method="get" action="<?php echo IRP_PAGE_SETTINGS?>">
64
+ <input type="hidden" name="page" value="<?php echo IRP_PLUGIN_SLUG?>" />
65
+ <input type="submit" class="button" value="CONTINUE USING FREE VERSION" />
66
+ </form>
67
+ </td>
68
+ <td style="text-align: left; vertical-align: top;">
69
+ <form method="get" action="<?php echo IRP_PAGE_PREMIUM?>">
70
+ <input type="hidden" name="utm_source" value="free-users" />
71
+ <input type="hidden" name="utm_medium" value="irp-whatsnew" />
72
+ <input type="hidden" name="utm_campaign" value="IRP" />
73
+ <input type="submit" class="button-primary" value="UPGRADE TO PREMIUM NOW ››" />
74
+ </form>
75
+ <a href="<?php echo irp_preview_link()?>" target="_blank">or preview your posts with PRO themes</a>
76
+ </td>
77
+ </tr>
78
+ </table>
79
+ <?php }
80
+
81
+ function irp_preview_link() {
82
+ global $irp;
83
+
84
+ $options=array(
85
+ 'count'=>1
86
+ , 'array'=>TRUE
87
+ , 'numberposts'=>5
88
+ );
89
+ $posts=wp_get_recent_posts($options);
90
+ $ids=array();
91
+ foreach($posts as $p) {
92
+ $ids[]=$p['ID'];
93
+ }
94
+ shuffle($ids);
95
+ $options=irp_ui_get_box($ids, $options);
96
+
97
+ $options=array(
98
+ 'ctaText'=>urlencode($options['ctaText'])
99
+ , 'postTitle'=>urlencode($options['postTitle'])
100
+ , 'postImageUrl'=>urlencode($options['postImageUrl'])
101
+ );
102
+ $uri=IRP_PAGE_PREMIUM;
103
+ $uri=add_query_arg($options, $uri);
104
+ return $uri;
105
+ }
includes/classes/common/Stack.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ class IRP_Stack {
5
+ var $array;
6
+
7
+ public function __construct() {
8
+ $this->array=array();
9
+ }
10
+
11
+ public function push($v) {
12
+ array_push($this->array, $v);
13
+ }
14
+ public function pop() {
15
+ $v=array_pop($this->array);
16
+ return $v;
17
+ }
18
+ public function peek() {
19
+ return $this->array[count($this->array)-1];
20
+ }
21
+ public function size() {
22
+ return count($this->array);
23
+ }
24
+ public function isEmpty() {
25
+ return (count($this->array)==0);
26
+ }
27
+ }
includes/classes/core/HtmlTemplate.php ADDED
@@ -0,0 +1,297 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ class IRP_HtmlTemplate {
5
+ var $templates;
6
+ var $defaults;
7
+
8
+ public function __construct() {
9
+ $this->templates=array();
10
+ $this->defaults=array();
11
+ }
12
+
13
+ public function getTemplates() {
14
+ return $this->templates;
15
+ }
16
+ public function getDefaults() {
17
+ return $this->defaults;
18
+ }
19
+ public function getTemplatesNames() {
20
+ $array=array_keys($this->templates);
21
+ asort($array);
22
+ return $array;
23
+ }
24
+ public function getFields($name) {
25
+ return $this->getFieldsOrBody($name);
26
+ }
27
+ public function getBody($name, $values=array()) {
28
+ return $this->getFieldsOrBody($name, $values);
29
+ }
30
+ private function getFieldsOrBody($name, $values=array()) {
31
+ global $irp;
32
+
33
+ if(!is_array($values)) {
34
+ $values=array();
35
+ }
36
+
37
+ $buffer='';
38
+ $fields=array();
39
+ $fields['template']='template';
40
+ if(isset($this->templates[$name])) {
41
+ $body=$this->templates[$name];
42
+ $len=strlen($body);
43
+ $previous=0;
44
+ while($previous<$len) {
45
+ $start=strpos($body, '{', $previous);
46
+ if($start!==FALSE) {
47
+ if($previous!=$start) {
48
+ $text=$irp->Utils->substr($body, $previous, $start);
49
+ $buffer.=$text;
50
+ }
51
+ $end=strpos($body, '}', $start+1);
52
+ $another=strpos($body, '{', $start+1);
53
+
54
+ if($end!==FALSE) {
55
+ if($another!==FALSE && $another<$end) {
56
+ $text=$irp->Utils->substr($body, $start, $another);
57
+ $buffer.=$text;
58
+ $previous=$another;
59
+ } else {
60
+ $k=$irp->Utils->substr($body, $start+1, $end);
61
+ if(trim($k)!='' && strpos($k, "\n")===FALSE) {
62
+ if($irp->Utils->startsWith($k, 'if ')) {
63
+ $k=substr($k, 3);
64
+ $fields[$k]=$k;
65
+ $v=$irp->Utils->get($values, $k, '#'.$k.'??#');
66
+ if($irp->Utils->isTrue($v)) {
67
+ //ok continue analysing the rest of template
68
+ //WARN: currently no nested if are allowed
69
+ } else {
70
+ $if='{/if}';
71
+ $start=strpos($body, $if, $end+1);
72
+ if($start===FALSE) {
73
+ $irp->Log->error("CHECK THE TEMPLATE. NO {/if} FOUND FOR {if %s}", $k);
74
+ break;
75
+ } else {
76
+ //skip all the text between {if xxx} and {/if}
77
+ $end=$start+strlen($if)-1;
78
+ }
79
+ }
80
+ } elseif($irp->Utils->startsWith($k, '/if')) {
81
+ //nothing
82
+ } else {
83
+ $fields[$k]=$k;
84
+ $v=$irp->Utils->get($values, $k, '#'.$k.'??#');
85
+ $buffer.=$v;
86
+ }
87
+ } else {
88
+ $text=$irp->Utils->substr($body, $start, $end+1);
89
+ $buffer.=$text;
90
+ }
91
+ $previous=$end+1;
92
+ }
93
+ } else {
94
+ $text=substr($body, $previous);
95
+ $buffer.=$text;
96
+ break;
97
+ }
98
+ } else {
99
+ $text=substr($body, $previous);
100
+ $buffer.=$text;
101
+ break;
102
+ }
103
+ }
104
+ }
105
+ $fields=array_keys($fields);
106
+ $buffer=str_replace("\n\n", "\n", $buffer);
107
+ $result=$buffer;
108
+ if(!is_array($values) || $values==NULL) {
109
+ $result=$fields;
110
+ }
111
+ return $result;
112
+ }
113
+
114
+ //load html template from file system stored in .html files
115
+ public function load($file) {
116
+ if(!file_exists($file)) {
117
+ return;
118
+ }
119
+
120
+ $matchTemplate='#template';
121
+ $matchDefaults='#defaults';
122
+
123
+ $file=file_get_contents($file);
124
+ if($file!=NULL && strlen($file)>0) {
125
+ $file=str_replace("\r\n", "\n", $file);
126
+ $file=str_replace("\n\n", "\n", $file);
127
+ $file=explode("\n", $file);
128
+
129
+ $name='';
130
+ $html='';
131
+ foreach($file as $row) {
132
+ if(stripos($row, $matchTemplate)!==FALSE) {
133
+ if($html!='' && $name!='') {
134
+ $this->templates[$name]=$html;
135
+ }
136
+
137
+ $name=substr($row, strlen($matchTemplate)+1);
138
+ $name=trim($name);
139
+ $html='';
140
+ continue;
141
+ }
142
+ elseif(stripos($row, $matchDefaults)!==FALSE && $name!='') {
143
+ if($html!='' && $name!='') {
144
+ $this->templates[$name]=$html;
145
+ }
146
+
147
+ $defaults=substr($row, strlen($matchDefaults)+1);
148
+ $defaults=str_replace('{', '', $defaults);
149
+ $defaults=str_replace('}', '', $defaults);
150
+ $defaults=explode(',', $defaults);
151
+ $tmp=array();
152
+ foreach($defaults as $v) {
153
+ $v=explode('=', $v);
154
+ if(count($v)>1) {
155
+
156
+ }
157
+ $tmp[trim($v[0])]=trim($v[1]);
158
+ }
159
+ $this->defaults[$name]=$tmp;
160
+ continue;
161
+ }
162
+
163
+ if($name=='') {
164
+ continue;
165
+ }
166
+
167
+ $html.=$row."\n";
168
+ }
169
+
170
+ if($html!='' && $name!='') {
171
+ $this->templates[$name]=$html;
172
+ }
173
+ }
174
+ }
175
+ public function html($name, $values, $options='') {
176
+ global $irp;
177
+ $defaults=array(
178
+ 'includeCss'=>TRUE
179
+ );
180
+ $options=$irp->Utils->parseArgs($options, $defaults);
181
+
182
+ if(!is_array($values)) {
183
+ $values=array();
184
+ }
185
+ $values['template']=str_replace(' ', '-', $name);
186
+ $values['utemplate']=$irp->Options->getTemplateUUID($values['template']);
187
+ $values['assetsImages']=IRP_PLUGIN_ASSETS.'images/';
188
+ $values['assets']=IRP_PLUGIN_ASSETS;
189
+ $values['demoLink']=irp_preview_link();
190
+
191
+ if(isset($values['linkRel'])) {
192
+ $values['linkRel']=$values['linkRel'];
193
+ if($values['linkRel']!='nofollow') {
194
+ $values['linkRel']='';
195
+ }
196
+ }
197
+ $values['linkRel']=($values['linkRel']!='' ? 'rel="'.$values['linkRel'].'"' : '');
198
+
199
+ $style=array();
200
+ $code='';
201
+ if(isset($this->templates[$name])) {
202
+ foreach($values as $k=>$v) {
203
+ if(stripos($k, 'color')!==FALSE) {
204
+ $values[$k]=$irp->Options->getColor($values[$k]);
205
+ if($values[$k]=='') {
206
+ $values[$k]='inherit';
207
+ }
208
+ $values[$k.'Hover']=$irp->Options->getHoverColor($values[$k]);
209
+ if($values[$k.'Hover']=='') {
210
+ $values[$k.'Hover']='inherit';
211
+ }
212
+ } elseif(stripos($k, 'opacity')!==FALSE) {
213
+ $values[$k]=(intval($values[$k])/100);
214
+ }
215
+ $values[$k.'Display']=($irp->Utils->isTrue($values[$k]) ? 'block' : 'none');
216
+ $values[$k.'Visibility']=($irp->Utils->isTrue($values[$k]) ? 'visible' : 'hidden');
217
+ }
218
+ if(isset($values['comment']) && trim($values['comment'])!=''
219
+ && !$irp->Utils->startsWith($values['comment'], "<!--")) {
220
+ $values['comment']="<!-- ".trim($values['comment'])." //-->";
221
+ }
222
+
223
+ if($options['includeCss']) {
224
+ //generate unique id from all the combinations, this grant to use the same theme
225
+ //but with different color using shotcodes
226
+ $values['utemplate']=$irp->Utils->getUUID($values);
227
+ }
228
+ $code=$this->getBody($name, $values);
229
+ if(!$options['includeCss']) {
230
+ $array=explode("\n", $code);
231
+ $code=array();
232
+
233
+ $css=FALSE;
234
+ foreach($array as $row) {
235
+ if (stripos($row, '<style>') !== FALSE) {
236
+ $css = TRUE;
237
+ if(!$options['includeCss']) {
238
+ $style[]=$row;
239
+ $row='';
240
+ }
241
+ } elseif (stripos($row, '</style>') !== FALSE) {
242
+ $css = FALSE;
243
+ if(!$options['includeCss']) {
244
+ $style[]=$row;
245
+ $row='';
246
+ }
247
+ } elseif ($css) {
248
+ if(!$options['includeCss']) {
249
+ $style[]=$row;
250
+ $row='';
251
+ }
252
+ }
253
+
254
+ if(trim($row)!='') {
255
+ $code[]=$row;
256
+ }
257
+ }
258
+ $code=implode("\n", $code);
259
+ if(count($style)>0) {
260
+ $irp->Options->pushCssStyle($style);
261
+ }
262
+ }
263
+ }
264
+
265
+ $code=$irp->Utils->trimCode($code);
266
+ if($code!='') {
267
+ if(isset($values['hasPoweredBy']) && $values['hasPoweredBy']) {
268
+ $code.='<div style="width:100%; text-align:right; font-weight:normal;">';
269
+ $code.='<div style="font-size:10px;">';
270
+ $code.='<span class="poweredByText">Powered by</span>';
271
+ $code.='&nbsp;';
272
+ $code.='<a rel="nofollow" style="font-weight:bold;" href="https://wordpress.org/plugins/intelly-related-posts/" target="_blank">';
273
+ $code.='Inline Related Posts';
274
+ $code.='</a>';
275
+ $code.='</div>';
276
+ $code.='</div>';
277
+ $code.='<div style="clear:both"></div>';
278
+ }
279
+ $mt=$irp->Options->getMarginTop();
280
+ $mb=$irp->Options->getMarginBottom();
281
+ $code='<div style="clear:both; margin-top:'.$mt.'; margin-bottom:'.$mb.';">'.$code.'</div>';
282
+ //$code.="\n";
283
+ //$code.="<br>";
284
+ }
285
+
286
+ $defaults=$irp->HtmlTemplate->getDefaults();
287
+ $defaults=$defaults[$options['template']];
288
+ if($code!='' && isset($defaults['proTheme']) && $irp->Utils->isTrue($defaults['proTheme'])) {
289
+ $code.='<p style="text-align:center;">';
290
+ $code.='<a style="font-size:20px; color:green; font-weight:bold;" href="'.$values['demoLink'].'" rel="nofollow" target="_blank">';
291
+ $code.='Click here to preview your posts with PRO themes ››';
292
+ $code.='</p>';
293
+ $code.='</a>';
294
+ }
295
+ return $code;
296
+ }
297
+ }
includes/classes/core/Manager.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) exit;
3
+
4
+ class IRP_Manager {
5
+
6
+ public function __construct() {
7
+
8
+ }
9
+
10
+ public function getRelatedPostsIds($args) {
11
+ global $irp;
12
+
13
+ $ids=array();
14
+ if(IRP_DISABLE_RELATED || !$irp->Options->isActive()) {
15
+ return $ids;
16
+ }
17
+
18
+ $defaults=array('postId'=>0
19
+ , 'posts'=>array(), 'cats'=>array(), 'tags'=>array()
20
+ , 'count'=>10
21
+ , 'shuffle'=>FALSE);
22
+ $args=$irp->Utils->parseArgs($args, $defaults);
23
+
24
+ $args['posts']=$irp->Utils->toCommaArray($args['posts']);
25
+ $args['cats']=$irp->Utils->toCommaArray($args['cats']);
26
+ $args['tags']=$irp->Utils->toCommaArray($args['tags']);
27
+ $args['postId']=intval($args['postId']);
28
+ if($args['postId']>0) {
29
+ $options=array('orderby' => 'name', 'order' => 'ASC', 'fields' => 'ids');
30
+ $args['tags']=wp_get_post_tags($args['postId'], $options);
31
+ $args['cats']=wp_get_post_categories($args['postId']);
32
+ }
33
+
34
+ if(count($args['posts'])>0) {
35
+ $ids=$args['posts'];
36
+ } else {
37
+ $ids=array();
38
+ switch ($irp->Options->getEngineSearch()) {
39
+ case IRP_ENGINE_SEARCH_CATEGORIES:
40
+ $ids=$this->queryRelatedPostsIds($args, 'category__in', $args['cats']);
41
+ break;
42
+ case IRP_ENGINE_SEARCH_TAGS:
43
+ $ids=$this->queryRelatedPostsIds($args, 'tag__in', $args['tags']);
44
+ break;
45
+ case IRP_ENGINE_SEARCH_CATEGORIES_TAGS:
46
+ //if we execute this query with the 2 parameters togheter category__in
47
+ //and tag__in WP do an AND query and not an OR query as we need
48
+ $cats=$this->queryRelatedPostsIds($args, 'category__in', $args['cats']);
49
+ $tags=$this->queryRelatedPostsIds($args, 'tag__in', $args['tags']);
50
+ $ids=array_merge($cats, $tags);
51
+ $ids=array_unique($ids);
52
+ break;
53
+ }
54
+ }
55
+
56
+ if($args['shuffle']) {
57
+ shuffle($ids);
58
+ }
59
+ return $ids;
60
+ }
61
+
62
+ private function queryRelatedPostsIds($args, $optionKey, $optionArray) {
63
+ global $irp;
64
+
65
+ $ids=array();
66
+ if(!is_array($optionArray) || count($optionArray)==0) {
67
+ return $ids;
68
+ }
69
+
70
+ $post=$irp->Options->getPostShown();
71
+ $options=array(
72
+ 'post_type'=>$post->post_type
73
+ //, 'nopaging'=>TRUE
74
+ , 'posts_per_page'=>10
75
+ , 'post_status'=>'publish'
76
+ , 'post__not_in'=>array($post->ID)
77
+ , 'orderby'=>'rand'
78
+ );
79
+ $days=$irp->Options->getRewritePostsDays();
80
+ if($days>0) {
81
+ $options['date_query'] = array(
82
+ 'column' => 'post_date'
83
+ , 'after' => '- '.$days.' days'
84
+ );
85
+ }
86
+ $options[$optionKey]=$optionArray;
87
+
88
+ $q=new WP_Query();
89
+ $irp->Log->debug('RELATED POSTS QUERY=%s', $options);
90
+ $posts=$q->query($options);
91
+
92
+ $irp->Log->debug('RELATED POSTS RESULT COUNT=%s', count($posts));
93
+ foreach($posts as $p) {
94
+ if($args['postId']<=0 || $args['postId']!=$p->ID) {
95
+ $ids[]=$p->ID;
96
+ }
97
+ }
98
+ return $ids;
99
+ }
100
+ }
includes/classes/core/Singleton.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class IRP_Singleton {
3
+ var $Lang;
4
+ var $Utils;
5
+ var $Form;
6
+ var $Check;
7
+ var $Options;
8
+ var $Manager;
9
+ var $Log;
10
+ var $Cron;
11
+ var $Tracking;
12
+ var $Tabs;
13
+ var $Plugin;
14
+ var $HtmlTemplate;
15
+
16
+ function __construct() {
17
+ $this->Lang=new IRP_Language();
18
+ $this->Utils=new IRP_Utils();
19
+ $this->Form=new IRP_Form();
20
+ $this->Check=new IRP_Check();
21
+ $this->Options=new IRP_AppOptions();
22
+ $this->Manager=new IRP_Manager();
23
+ $this->Log=new IRP_Logger();
24
+ $this->Cron=new IRP_Cron();
25
+ $this->Tracking=new IRP_Tracking();
26
+ $this->Tabs=new IRP_Tabs();
27
+ $this->Plugin=new IRP_Plugin();
28
+ $this->HtmlTemplate=new IRP_HtmlTemplate();
29
+ }
30
+ function init() {
31
+ $this->Lang->load('irp', IRP_PLUGIN_ROOT.'languages/Lang.txt');
32
+ $this->HtmlTemplate->load(IRP_PLUGIN_ROOT.'assets/templates/styles.html');
33
+ $this->Tabs->init();
34
+ $this->Cron->init();
35
+ }
36
+ }
includes/classes/html/BehaviourTag.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ class IRP_BehaviourTag extends IRP_HTMLTag {
5
+
6
+ var $allowBoxBefore=FALSE;
7
+ var $allowBoxAfter=FALSE;
8
+ var $skipWordsCount=FALSE;
9
+ var $ensureUncuttable=FALSE;
10
+ var $ensureWithoutPreviousBox=FALSE;
11
+ var $ensureWithoutNextBox=FALSE;
12
+
13
+ public function write(IRP_HTMLContext $context) {
14
+ $w=$context->skipWordsCount;
15
+ $context->skipWordsCount=$this->skipWordsCount;
16
+
17
+ if($this->ensureWithoutPreviousBox) {
18
+ //if present remove the last related box
19
+ $args=array('last'=>TRUE);
20
+ $context->popRelatedBox($args);
21
+ }
22
+ if($this->allowBoxBefore) {
23
+ $context->writeRelatedBoxIfNeeded();
24
+ }
25
+
26
+ if($this->ensureUncuttable) {
27
+ $previous=$context->isUncuttable();
28
+ $context->setUncuttable(TRUE);
29
+ }
30
+ parent::write($context);
31
+ if($this->ensureUncuttable) {
32
+ $context->setUncuttable($previous);
33
+ }
34
+
35
+ if($this->allowBoxAfter) {
36
+ $context->writeRelatedBoxIfNeeded();
37
+ }
38
+ if($this->ensureWithoutNextBox) {
39
+ $context->setWithoutNextBox();
40
+ }
41
+
42
+ $context->skipWordsCount=$w;
43
+ }
44
+ public function analyseText(IRP_HTMLContext $context) {
45
+ if($this->skipWordsCount) {
46
+ return;
47
+ }
48
+
49
+ parent::analyseText($context);
50
+ }
51
+ }
includes/classes/html/HTMLContext.php ADDED
@@ -0,0 +1,564 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ class IRP_HTMLContext {
5
+ var $root; //MainTag
6
+ var $buffer; //IRP_Stack
7
+
8
+ var $uncuttable;
9
+ var $withoutNextState;
10
+ var $withoutNextWords;
11
+
12
+ var $currentWords;
13
+ var $lastBoxWords;
14
+ //last time that the plugin insert the related posts box counter values
15
+ var $wordsThreshold;
16
+ var $skipWordsCount=FALSE;
17
+
18
+ public function __construct() {
19
+ $this->clearBuffer();
20
+ }
21
+
22
+ public function setWithoutNextBox() {
23
+ $this->withoutNextState=TRUE;
24
+ $this->withoutNextWords=$this->currentWords;
25
+ }
26
+ public function isSkipCurrentBox() {
27
+ $result=FALSE;
28
+ if($this->withoutNextState) {
29
+ //if i already had written some words i can unlock the withoutNext lock
30
+ $result=($this->currentWords<=$this->withoutNextWords);
31
+ if(!$result) {
32
+ $this->withoutNextState=FALSE;
33
+ $this->withoutNextWords=0;
34
+ }
35
+ }
36
+ return $result;
37
+ }
38
+ public function clearSkipNext() {
39
+ $this->withoutNextState=FALSE;
40
+ $this->withoutNextWords=0;
41
+ }
42
+
43
+ public function setUncuttable($value) {
44
+ $this->uncuttable=$value;
45
+ }
46
+ public function isUncuttable() {
47
+ return $this->uncuttable;
48
+ }
49
+
50
+ private function clearBuffer() {
51
+ $this->buffer=new IRP_Stack();
52
+ $this->uncuttable=FALSE;
53
+ $this->isParentTable=FALSE;
54
+ $this->withoutNextState=FALSE;
55
+ $this->currentWords=0;
56
+ $this->lastBoxWords=0;
57
+ $this->withoutNextState=FALSE;
58
+ $this->withoutNextWords=0;
59
+ }
60
+ private function pushTextContent($part, $text, IRP_Stack &$tagsStack) {
61
+ if(!$part) {
62
+ $parent=$tagsStack->peek();
63
+ $part=new IRP_TextContent();
64
+ $parent->pushTag($part);
65
+ }
66
+ $part->append($text);
67
+ return $part;
68
+ }
69
+
70
+ public function isWriteRelatedBox() {
71
+ global $irp;
72
+ if($this->isSkipCurrentBox()) {
73
+ return FALSE;
74
+ }
75
+ if($this->isUncuttable()) {
76
+ return FALSE;
77
+ }
78
+
79
+ $irp->Log->debug('WriteRelatedBox?');
80
+ $diff=($this->currentWords-$this->lastBoxWords);
81
+ $irp->Log->debug('currentWords[%s]-lastBoxWords[%s]=diff[%s]'
82
+ , $this->currentWords, $this->lastBoxWords, $diff);
83
+
84
+ $postLimit=$this->wordsThreshold*($irp->Options->getRewriteBoxesWritten()+1);
85
+ $irp->Log->debug('wordsThreshold[%s]*(RewriteBoxesWritten[%s]+1)=postLimit[%s]'
86
+ , $this->wordsThreshold, $irp->Options->getRewriteBoxesWritten(), $postLimit);
87
+
88
+ $minLimit=$irp->Options->getRewriteThreshold();
89
+ $result=($this->currentWords>=$postLimit && $diff>=$minLimit);
90
+ $irp->Log->debug('(currentWords[%s]>=postLimit[%s]) AND (diff[%s]>=minLimit[%s])=%s'
91
+ , $this->currentWords, $postLimit
92
+ , $diff, $minLimit, $result);
93
+ return $result;
94
+ }
95
+
96
+ function getTagAttribute($fullTag, $name) {
97
+ $close=strpos($fullTag, '>');
98
+ $attr=strpos($fullTag, ' '.$name.'=');
99
+ $result='';
100
+ if($attr!==FALSE && $close!==FALSE && $attr<$close) {
101
+ $quote=substr($fullTag, $attr+strlen($name)+2, 1);
102
+ $text=substr($fullTag, $attr+strlen($name)+3);
103
+ $end=strpos($text, $quote, 1);
104
+ if($end!==FALSE) {
105
+ $result=substr($text, 0, $end);
106
+ }
107
+ }
108
+ return $result;
109
+ }
110
+
111
+ //get the tag name to lower case, could be that is not defined
112
+ //so this function return '' could also be that
113
+ function getTagName($fullTag) {
114
+ global $irp;
115
+
116
+ $start=1;
117
+ $p=strpos($fullTag, ' ');
118
+ if($p===FALSE) {
119
+ $p=strpos($fullTag, '/');
120
+ if($p!==FALSE && $p==1) {
121
+ $start=2;
122
+ $p=FALSE;
123
+ }
124
+ if($p===FALSE) {
125
+ $p=strpos($fullTag, '>');
126
+ if($p===FALSE) {
127
+ $irp->Log->error('UNABLE TO DECODE TAG %s', $fullTag);
128
+ return '';
129
+ }
130
+ }
131
+ }
132
+ $tag=trim(substr($fullTag, $start, $p-$start));
133
+ $tag=strtolower($tag);
134
+ return $tag;
135
+ }
136
+ function getHtmlTag($fullTag){
137
+ global $irp;
138
+
139
+ $tag=$this->getTagName($fullTag);
140
+ $tagId=$this->getTagAttribute($fullTag, 'id');
141
+ $tagClasses=$this->getTagAttribute($fullTag, 'class');
142
+ if($tagClasses!=='') {
143
+ $tagClasses=explode(' ', $tagClasses);
144
+ } else {
145
+ $tagClasses=array();
146
+ }
147
+
148
+ if($tag=='') {
149
+ return NULL;
150
+ }
151
+
152
+ $result=new IRP_OtherTag();
153
+ if(in_array($tag, array('h1','h2','h3','h4','h5','h6'))) {
154
+ $result=new IRP_BehaviourTag();
155
+ $result->allowBoxBefore=TRUE;
156
+ $result->ensureUncuttable=TRUE;
157
+ $result->ensureWithoutNextBox=TRUE;
158
+ } elseif(in_array($tag, array('ul', 'ol', 'dl'))) {
159
+ $result=new IRP_BehaviourTag();
160
+ $result->ensureWithoutPreviousBox=TRUE;
161
+ $result->ensureUncuttable=TRUE;
162
+ $result->allowBoxAfter=TRUE;
163
+ } elseif(in_array($tag, array('area','base','col','br','command','embed','hr','img','input','link','meta','param','source'))) {
164
+ $result=new IRP_SingletonTag();
165
+ } elseif(in_array($tag, array('iframe'))) {
166
+ $result=new IRP_BehaviourTag();
167
+ $result->allowBoxBefore=TRUE;
168
+ $result->ensureUncuttable=TRUE;
169
+ $result->allowBoxAfter=TRUE;
170
+ $result->skipWordsCount=TRUE;
171
+ } elseif(in_array($tag, array('table'))) {
172
+ $result=new IRP_BehaviourTag();
173
+ $result->allowBoxBefore=TRUE;
174
+ $result->ensureUncuttable=TRUE;
175
+ $result->allowBoxAfter=TRUE;
176
+ } elseif(in_array($tag, array('span'))) {
177
+ $result=new IRP_BehaviourTag();
178
+ $result->ensureWithoutPreviousBox=TRUE;
179
+ $result->ensureWithoutNextBox=TRUE;
180
+ } elseif(in_array($tag, array('figure'))) {
181
+ $result=new IRP_BehaviourTag();
182
+ $result->ensureWithoutNextBox=TRUE;
183
+ $result->skipWordsCount=TRUE;
184
+ $result->ensureUncuttable=TRUE;
185
+ } elseif(in_array($tag, array('div'))) {
186
+ $result=new IRP_BehaviourTag();
187
+ $result->ensureWithoutPreviousBox=TRUE;
188
+ $result->ensureWithoutNextBox=TRUE;
189
+
190
+ $ids=explode('|', 'optinforms-|wpautbox-|wpurp-container-recipe-');
191
+ if($irp->Utils->startsWith($tagId, $ids)) {
192
+ $result->skipWordsCount=TRUE;
193
+ $result->ensureUncuttable=TRUE;
194
+ }
195
+
196
+ $classes=explode('|', 'yuzo_related_post|shareaholic-|wp-caption|wordpress-post-tabs|amp-wp-article-content|title-wrapper|sa-source-wrapper|et_pb_text_inner|wprm-recipe-name|toc_light_blue|ast-oembed-container|depiction|wc-tab|gkblock-3|et_pb_toggle_content|et_pb_module|aawp-product__description|fusion-text|fusion-alert-content|mv-create-instructions|recipe-ingredients-wrap|guide-box|underPostOptin|x-columnize');
197
+ if($irp->Utils->startsWith($tagClasses, $classes)) {
198
+ $result->skipWordsCount=TRUE;
199
+ $result->ensureUncuttable=TRUE;
200
+ }
201
+ } elseif(in_array($tag, array('p'))) {
202
+ $result=new IRP_BehaviourTag();
203
+ $result->allowBoxBefore=TRUE;
204
+ $result->allowBoxAfter=TRUE;
205
+ } elseif(in_array($tag, array('blockquote', 'cite', 'code', 'em', 'pre'))) {
206
+ $result=new IRP_BehaviourTag();
207
+ $result->ensureWithoutPreviousBox=TRUE;
208
+ $result->ensureUncuttable=TRUE;
209
+ $result->ensureWithoutNextBox=TRUE;
210
+ } elseif(in_array($tag, array('irp', 'script', 'style'))) {
211
+ $result=new IRP_BehaviourTag();
212
+ $result->ensureWithoutPreviousBox=TRUE;
213
+ $result->ensureUncuttable=TRUE;
214
+ $result->ensureWithoutNextBox=TRUE;
215
+ $result->skipWordsCount=TRUE;
216
+ } elseif(in_array($tag, array('sub', 'sup'))) {
217
+ $result=new IRP_BehaviourTag();
218
+ $result->ensureUncuttable=TRUE;
219
+ }
220
+ return $result;
221
+ }
222
+
223
+ public function decode($all) {
224
+ global $irp;
225
+
226
+ $this->root=new IRP_MainTag();
227
+ $this->clearBuffer();
228
+
229
+ if(!$all || trim($all)=='') return FALSE;
230
+
231
+ //qui sono a ricercare tutti i tag per poi farci delle verifiche
232
+ $tagsStack=new IRP_Stack();
233
+ $tagsStack->push($this->root);
234
+
235
+ $errors=FALSE;
236
+ $part=NULL;
237
+ $previous=0;
238
+
239
+ try {
240
+ do {
241
+ $less=strpos($all, '<', $previous);
242
+ if($less===FALSE) {
243
+ if($previous!=strlen($all)) {
244
+ $text=$irp->Utils->substrln($all, $previous);
245
+ $part=$this->pushTextContent($part, $text, $tagsStack);
246
+ }
247
+ break;
248
+ }
249
+
250
+ if($previous!=$less) {
251
+ $text=$irp->Utils->substrln($all, $previous, $less);
252
+ $part=$this->pushTextContent($part, $text, $tagsStack);
253
+ }
254
+
255
+ $more=strpos($all, '>', $less+1);
256
+ $another=strpos($all, '<', $less+1);
257
+ if($more===FALSE) {
258
+ //only open tag so I considate all as text (in this case is better
259
+ //to use html code like &gt; or &lt;
260
+ $text=$irp->Utils->substrln($all, $previous);
261
+ $part=$this->pushTextContent($part, $text, $tagsStack);
262
+ break;
263
+ }
264
+
265
+ if($another!==FALSE && $another<$more) {
266
+ //something like this <bla bla bla <bla bla> so we considerate
267
+ //from the last < before >
268
+ $previous=$another;
269
+ $text=$irp->Utils->substrln($all, $less, $previous);
270
+ $part=$this->pushTextContent($part, $text, $tagsStack);
271
+ continue;
272
+ }
273
+
274
+ $previous=$more+1;
275
+ $text=$irp->Utils->substrln($all, $less, $previous);
276
+ $parent=$tagsStack->peek();
277
+ $tag=$this->getOpenTag($text);
278
+ if($tag) {
279
+ //detected tag open
280
+ $part=NULL;
281
+ $parent->pushTag($tag);
282
+ if($tag->hasTagContent()) {
283
+ //this tag contains a content
284
+ $tagsStack->push($tag);
285
+ }
286
+ } else {
287
+ //detected tag close
288
+ $tag=$this->getCloseTag($text, $tagsStack);
289
+ if($tag) {
290
+ $part=NULL;
291
+ $compare=$tagsStack->pop();
292
+ while(!$tagsStack->isEmpty() && $compare!=$tag) {
293
+ //security check: close each tag until i found my tag
294
+ $irp->Log->error('WHAT? UNABLE TO FIND OPENED TAG..TRY CLOSING AND RETRYING AGAIN');
295
+ $compare->closeTag='</'.$compare->tag.'>';
296
+ $compare=$tagsStack->pop();
297
+ }
298
+ if($compare!=$tag) {
299
+ $irp->Log->error('WHAT? UNABLE TO FIND OPENED TAG');
300
+ $errors=TRUE;
301
+ } else {
302
+ $compare->closeTag=$text;
303
+ }
304
+ } else {
305
+ //simply text
306
+ $part=$this->pushTextContent($part, $text, $tagsStack);
307
+ }
308
+ }
309
+ }
310
+ while($previous<strlen($all));
311
+ } catch(Exception $ex) {
312
+ $irp->Log->exception($ex);
313
+ }
314
+
315
+ return !$errors;
316
+ }
317
+
318
+ private function getOpenTag($openTag) {
319
+ global $irp;
320
+ if($irp->Utils->startsWith($openTag, '</')) {
321
+ return NULL;
322
+ }
323
+
324
+ $name=$this->getTagName($openTag);
325
+ $tag=$this->getHtmlTag($openTag);
326
+ if($tag) {
327
+ $tag->tag=$name;
328
+ $tag->openTag=$openTag;
329
+ }
330
+ return $tag;
331
+ }
332
+ private function getCloseTag($closeTag, IRP_Stack $tagsStack) {
333
+ global $irp;
334
+ if(!$irp->Utils->startsWith($closeTag, '</')) {
335
+ return NULL;
336
+ }
337
+
338
+ $compare=$this->getTagName($closeTag);
339
+ if($compare=='') return NULL;
340
+
341
+ $tos=$tagsStack->peek();
342
+ if(!$tos || !isset($tos->tag) || strcasecmp($tos->tag, $compare)!=0) {
343
+ $irp->Log->error('CHECK YOU BODY TAG %s ENDS WITH %s TAG', $tos->tag, $compare);
344
+ return NULL;
345
+ }
346
+
347
+ $tos->closeTag=$closeTag;
348
+ return $tos;
349
+ }
350
+
351
+ public function execute($body) {
352
+ global $irp;
353
+ if(!$irp->Options->isRewriteActive()) {
354
+ return $body;
355
+ }
356
+
357
+ $this->decode($body);
358
+ $this->root->analyseText($this);
359
+ $t=intval($this->currentWords/($irp->Options->getRewriteBoxesCount()+1));
360
+ if($t<$irp->Options->getRewriteThreshold()) {
361
+ $t=$irp->Options->getRewriteThreshold();
362
+ }
363
+ /*
364
+ if($t<$irp->Options->getRewriteThreshold()) {
365
+ if($irp->Options->isRewriteAtEnd()) {
366
+ //this avoid to write a box just before the end of the posts
367
+ //where, due the isRewriteAtEnd flag we will write another box
368
+ $t=$this->wordsCounter+1;
369
+ } else {
370
+ $t=$irp->Options->getRewriteThreshold();
371
+ }
372
+ }
373
+ */
374
+ $this->wordsThreshold=$t;
375
+
376
+ $this->clearBuffer();
377
+ $this->root->write($this);
378
+
379
+ $result='';
380
+ foreach($this->buffer->array as $v) {
381
+ $result.=$v->getText();
382
+ }
383
+ return $result;
384
+ }
385
+ public function write($text, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
386
+ global $irp;
387
+ if(!$text || $text=='') return;
388
+ $text=$irp->Utils->format($text, $v1, $v2, $v3, $v4, $v5);
389
+
390
+ $v=NULL;
391
+ $new=$this->buffer->isEmpty();
392
+ if(!$new) {
393
+ $v=$this->buffer->peek();
394
+ if(!$v->isBufferText()) {
395
+ $new=TRUE;
396
+ }
397
+ }
398
+
399
+ if($new) {
400
+ $v=new IRP_BufferText();
401
+ $this->buffer->push($v);
402
+ }
403
+ $v->appendText($text);
404
+ }
405
+ public function writeRelatedBoxIfNeeded() {
406
+ $result=FALSE;
407
+ //write the box at the end of the tag only if this is not an <Hn> tag
408
+ if($this->isWriteRelatedBox()) {
409
+ $result=$this->writeRelatedBox();
410
+ }
411
+ return $result;
412
+ }
413
+ public function writeRelatedBox($forceBox=FALSE) {
414
+ global $irp;
415
+
416
+ $written=$irp->Options->getRewriteBoxesWritten();
417
+ $max=$irp->Options->getRewriteBoxesCount();
418
+ if(!$forceBox && $written>=$max) {
419
+ $irp->Log->error('MAX BOX=%s REACHED', $max);
420
+ return FALSE;
421
+ }
422
+
423
+ $irp->Log->debug('WRITING BOX=%s/%s', $written+1, $max);
424
+ $result=FALSE;
425
+ $count=1;//$irp->Options->getRewritePostsInBoxCount();
426
+ $ids=$irp->Options->getToShowPostsIds($count, TRUE);
427
+
428
+ $comment="INLINE RELATED POSTS %s/%s";
429
+ $comment=sprintf($comment, $written+1, $max);
430
+ $options=array(
431
+ 'comment'=>$comment
432
+ , 'shortcode'=>FALSE
433
+ );
434
+ $box=irp_ui_get_box($ids, $options);
435
+ if($box!='') {
436
+ $this->pushRelatedBox($box);
437
+ $result=TRUE;
438
+ } else {
439
+ $result=FALSE;
440
+ $irp->Log->error('NO BOX TO WRITE WITH IDS=%s', $ids);
441
+ }
442
+ return $result;
443
+ }
444
+ //append related-box element to buffer
445
+ public function pushRelatedBox($box) {
446
+ global $irp;
447
+
448
+ $v=new IRP_BufferBox();
449
+ $v->appendText($box);
450
+ $v->currentBoxWords=$this->currentWords;
451
+ $v->previousBoxWords=$this->lastBoxWords;
452
+ $this->buffer->push($v);
453
+
454
+ $written=$irp->Options->getRewriteBoxesWritten()+1;
455
+ $irp->Options->setRewriteBoxesWritten($written);
456
+ $this->lastBoxWords=$v->currentBoxWords;
457
+ }
458
+ //remove related-box elements from buffer starting from the end
459
+ public function popRelatedBox($args=NULL) {
460
+ global $irp;
461
+ if($this->buffer->isEmpty()) {
462
+ return FALSE;
463
+ }
464
+
465
+ $result=FALSE;
466
+ $defaults=array('last'=>TRUE, 'all'=>FALSE);
467
+ $args=$irp->Utils->parseArgs($args, $defaults);
468
+ if($args['last']) {
469
+ $v=$this->buffer->peek();
470
+ if($v->isBufferBox()) {
471
+ $v=$this->buffer->pop();
472
+ $this->lastBoxWords=$v->previousBoxWords;
473
+ $result=TRUE;
474
+
475
+ $w=$irp->Options->getRewriteBoxesWritten()-1;
476
+ $irp->Options->setRewriteBoxesWritten($w);
477
+ }
478
+ } elseif($args['all']) {
479
+ $array=array();
480
+ for($i=0; $i<count($this->buffer->array); $i++) {
481
+ $v=$this->buffer->array[$i];
482
+ if($v->isBufferBox()) {
483
+ $result=TRUE;
484
+ } else {
485
+ $array[]=$v;
486
+ }
487
+ }
488
+ $this->buffer->array=$array;
489
+ $this->lastBoxWords=0;
490
+ $irp->Options->setRewriteBoxesWritten(0);
491
+ }
492
+ return $result;
493
+ }
494
+ public function incCounters($text){
495
+ global $irp;
496
+ if($this->skipWordsCount) {
497
+ return;
498
+ }
499
+
500
+ $text=trim($text);
501
+ $words=explode(' ', $text);
502
+ $c=0;
503
+ foreach($words as $w) {
504
+ $w=trim($w);
505
+ if($w!='' && strlen($w)>1) {
506
+ $c++;
507
+ }
508
+ }
509
+
510
+ $this->currentWords+=$c;
511
+ $irp->Log->debug('TEXT=[%s] INCREMENT WORDS words[%s]/currentWords[%s]'
512
+ , $text, $c, $this->currentWords);
513
+ }
514
+ }
515
+
516
+ class IRP_BufferElement {
517
+ var $text;
518
+ public function __construct() {
519
+ $this->text='';
520
+ }
521
+
522
+ public function getText() {
523
+ return $this->text;
524
+ }
525
+ public function appendText($text) {
526
+ $this->text.=$text;
527
+ }
528
+
529
+ public function isBufferBox() {
530
+ return FALSE;
531
+ }
532
+ public function isBufferText() {
533
+ return FALSE;
534
+ }
535
+ }
536
+ class IRP_BufferText extends IRP_BufferElement {
537
+ public function __construct() {
538
+ parent::__construct();
539
+ }
540
+
541
+ public function isBufferBox() {
542
+ return FALSE;
543
+ }
544
+ public function isBufferText() {
545
+ return TRUE;
546
+ }
547
+ }
548
+ class IRP_BufferBox extends IRP_BufferElement {
549
+ var $currentBoxWords;
550
+ var $previousBoxWords;
551
+
552
+ public function __construct() {
553
+ parent::__construct();
554
+ $this->currentBoxWords=0;
555
+ $this->previousBoxWords=0;
556
+ }
557
+
558
+ public function isBufferBox() {
559
+ return TRUE;
560
+ }
561
+ public function isBufferText() {
562
+ return FALSE;
563
+ }
564
+ }
includes/classes/html/HTMLTag.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ class IRP_HTMLTag {
5
+ var $tags;
6
+ var $tag;
7
+ var $openTag;
8
+ var $closeTag;
9
+
10
+ public function __construct() {
11
+ $this->tags = array();
12
+ $this->tag='';
13
+ $this->openTag='';
14
+ $this->closeTag='';
15
+ }
16
+
17
+ public function hasTagContent() {
18
+ return TRUE;
19
+ }
20
+ public function pushTag(IRP_HTMLTag $child) {
21
+ if(count($this->tags)>0) {
22
+ //replace the TextContent tag that only contains \r\n with NewLineText
23
+ //due to now we use the substrln is impossible that we enter here
24
+ $last=$this->tags[count($this->tags)-1];
25
+ if(isset($last->body)) {
26
+ $newline=TRUE;
27
+ if($last->body=="\n" || $last->body=="\r\n") {
28
+ //we dont have to do nothing... sure this is a newlinetext!
29
+ } else {
30
+ for($i=0; $i<strlen($last->body); $i++) {
31
+ $c=substr($last->body, $i, 1);
32
+ if($c!="\n" && $c!="\n") {
33
+ $newline=FALSE;
34
+ break;
35
+ }
36
+ }
37
+ }
38
+
39
+ if($newline) {
40
+ $tag=new IRP_NewLineText();
41
+ $tag->body=$last->body;
42
+ $this->tags[count($this->tags)-1]=$tag;
43
+ }
44
+ }
45
+ }
46
+ $this->tags[] = $child;
47
+ }
48
+
49
+ public function write(IRP_HTMLContext $context) {
50
+ $context->write($this->openTag);
51
+ foreach($this->tags as $tag) {
52
+ $tag->write($context);
53
+ }
54
+ $context->write($this->closeTag);
55
+ }
56
+ public function analyseText(IRP_HTMLContext $context) {
57
+ foreach ($this->tags as $tag) {
58
+ $tag->analyseText($context);
59
+ }
60
+ }
61
+ }
includes/classes/html/MainTag.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ class IRP_MainTag extends IRP_HTMLTag {
5
+ public function __construct() {
6
+ parent::__construct();
7
+ }
8
+
9
+ public function write(IRP_HTMLContext $context) {
10
+ global $irp;
11
+ foreach ($this->tags as $tag) {
12
+ $tag->write($context);
13
+ }
14
+
15
+ //try to write the last box only if no boxes are written before
16
+ //this prevent from inserting at the end a box due to tipically
17
+ //marketer insert a CTA box (for instance download free book)
18
+ if($irp->Options->isRewriteAtEnd() && $irp->Options->getRewriteBoxesWritten()==0) {
19
+ $context->clearSkipNext();
20
+ $context->setUncuttable(FALSE);
21
+ $context->writeRelatedBox(TRUE);
22
+ } elseif(!$irp->Options->isRewriteAtEnd()) {
23
+ $args=array('last'=>TRUE);
24
+ $context->popRelatedBox($args);
25
+ }
26
+ }
27
+ }
includes/classes/html/NewLineText.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ class IRP_NewLineText extends IRP_TextContent {
5
+
6
+ public function __construct() {
7
+ parent::__construct();
8
+ }
9
+ public function hasTagContent() {
10
+ return FALSE;
11
+ }
12
+ public function append($text) {
13
+ $this->body.=$text;
14
+ }
15
+ public function write(IRP_HTMLContext $context) {
16
+ $context->write($this->body);
17
+ }
18
+ }
includes/classes/html/OtherTag.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ class IRP_OtherTag extends IRP_HTMLTag {
5
+ public function __construct() {
6
+ parent::__construct();
7
+ }
8
+
9
+ public function write(IRP_HTMLContext $context) {
10
+ parent::write($context);
11
+ }
12
+ }
includes/classes/html/SingletonTag.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ class IRP_SingletonTag extends IRP_HTMLTag {
5
+ public function __construct() {
6
+ parent::__construct();
7
+ }
8
+
9
+ public function hasTagContent() {
10
+ return FALSE;
11
+ }
12
+ public function write(IRP_HTMLContext $context) {
13
+ $context->write($this->openTag);
14
+ }
15
+ }
includes/classes/html/TextContent.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ class IRP_TextContent extends IRP_HTMLTag {
5
+ var $body;
6
+ public function __construct() {
7
+ parent::__construct();
8
+ $this->body='';
9
+ }
10
+
11
+ public function hasTagContent() {
12
+ return FALSE;
13
+ }
14
+ public function append($text) {
15
+ $this->body.=$text;
16
+ }
17
+ public function write(IRP_HTMLContext $context) {
18
+ global $irp;
19
+ if($context->isUncuttable() || trim($this->body)=='') {
20
+ //we dont want to insert nothing inside iframe or table
21
+ $context->write($this->body);
22
+ $context->incCounters($this->body);
23
+ if(defined('IRP_DEBUG_BLOCK') && IRP_DEBUG_BLOCK) {
24
+ $context->write(sprintf('<sup style="color:red;">&nbsp;{%s/%s,%s}</sup>'
25
+ , $context->currentWords, $context->wordsThreshold, $context->lastBoxWords));
26
+ }
27
+ } else {
28
+ //here is all text so we have to decide when cut it
29
+ $text=explode("\n", $this->body);
30
+ for($i=0; $i<count($text); $i++) {
31
+ $line=$text[$i];
32
+ if(trim($line)=='') {
33
+ $context->writeRelatedBoxIfNeeded();
34
+ }
35
+
36
+ if($i<(count($text)-1)) {
37
+ $line.="\n";
38
+ }
39
+ $context->write($line);
40
+ $context->incCounters($line);
41
+ if(trim($line)!='') {
42
+ if (defined('IRP_DEBUG_BLOCK') && IRP_DEBUG_BLOCK) {
43
+ $context->write(sprintf('<sup style="color:#008000">&nbsp;{%s/%s,%s}</sup>'
44
+ , $context->currentWords, $context->wordsThreshold, $context->lastBoxWords));
45
+ }
46
+ }
47
+ }
48
+ }
49
+ }
50
+ public function analyseText(IRP_HTMLContext $context) {
51
+ $context->incCounters($this->body);
52
+ }
53
+ }
includes/classes/ui/Check.php ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! defined( 'ABSPATH' ) ) exit;
4
+
5
+ class IRP_Check {
6
+ var $data;
7
+
8
+ public function __construct() {
9
+ $this->data=array_merge($_POST, $_GET);
10
+ }
11
+
12
+ public function is($name, $value, $ignoreCase=TRUE) {
13
+ $result=FALSE;
14
+ if(isset($this->data[$name])) {
15
+ if($ignoreCase) {
16
+ $result=(strtolower($this->data[$name])==strtolower($value));
17
+ } else {
18
+ $result=($this->data[$name]==$value);
19
+ }
20
+ }
21
+ return $result;
22
+ }
23
+ public function of($name, $default='') {
24
+ $result=$default;
25
+ if(isset($this->data[$name])) {
26
+ $result=$this->data[$name];
27
+ }
28
+ return $result;
29
+ }
30
+ public function nonce($action, $nonce='_wpnonce') {
31
+ if(isset($_REQUEST[$nonce])) {
32
+ $nonce=$_REQUEST[$nonce];
33
+ }
34
+ return wp_verify_nonce($nonce, $action);
35
+ }
36
+
37
+ //check if is a mandatory field by checking the .txt language file
38
+ private function error($name) {
39
+ global $irp;
40
+
41
+ $result=FALSE;
42
+ $k=$irp->Form->prefix.'.'.$name.'.check';
43
+ $v=$irp->Lang->L($k);
44
+ if($v!=$k) {
45
+ //this is a mandatory field so we give error
46
+ $irp->Options->pushErrorMessage($v);
47
+ $result=TRUE;
48
+ }
49
+ return $result;
50
+ }
51
+
52
+ public function value($name) {
53
+ $result='';
54
+ if(isset($this->data[$name])) {
55
+ $result=sanitize_text_field($this->data[$name]);
56
+ }
57
+ if($result=='') {
58
+ $this->error($name);
59
+ }
60
+ $this->data[$name]=$result;
61
+ return $result;
62
+ }
63
+ public function values($name) {
64
+ $result=array();
65
+ if(is_string($name)) {
66
+ $name=explode(',', $name);
67
+ }
68
+ foreach($name as $v) {
69
+ $result[]=$this->value(trim($v));
70
+ }
71
+ return $result;
72
+ }
73
+ public function email($name) {
74
+ $result=$this->value($name);
75
+ if($result!='') {
76
+ $result=sanitize_email($result);
77
+ if(!is_email($result)) {
78
+ $this->error($name);
79
+ }
80
+ }
81
+ $this->data[$name]=$result;
82
+ return $result;
83
+ }
84
+ public function float($name) {
85
+ $result=$this->value($name);
86
+ if($result!='' && !is_float($result)) {
87
+ $this->error($name);
88
+ }
89
+ $result=floatval($result);
90
+ $this->data[$name]=$result;
91
+ return $result;
92
+ }
93
+ public function integer($name) {
94
+ $result=$this->value($name);
95
+ if($result!='' && !is_int($result)) {
96
+ $this->error($name);
97
+ }
98
+ $result=intval($result);
99
+ $this->data[$name]=$result;
100
+ return $result;
101
+ }
102
+
103
+ public function hasErrors() {
104
+ global $irp;
105
+ return $irp->Options->hasErrorMessages();
106
+ }
107
+ }
includes/classes/ui/Form.php ADDED
@@ -0,0 +1,455 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! defined( 'ABSPATH' ) ) exit;
4
+
5
+ class IRP_Form {
6
+ var $prefix='Form';
7
+ var $labels=TRUE;
8
+ var $leftLabels=TRUE;
9
+ var $newline;
10
+ var $helps=FALSE;
11
+ var $selectIdField='id';
12
+
13
+ var $tags=FALSE;
14
+ var $tagNew=FALSE;
15
+ var $leftTags=FALSE;
16
+
17
+ public function __construct() {
18
+ }
19
+
20
+ //args can be a string or an associative array if you want
21
+ private function getTextArgs($args, $defaults, $excludes=array()) {
22
+ $result=$args;
23
+ if(is_string($excludes)) {
24
+ $excludes=explode(',', $excludes);
25
+ }
26
+ if(is_array($result) && count($result)>0) {
27
+ $result='';
28
+ foreach($args as $k=>$v) {
29
+ if(count($excludes)==0 || !in_array($k, $excludes)) {
30
+ $result.=' '.$k.'="'.$v.'"';
31
+ }
32
+ }
33
+ } elseif(!$args) {
34
+ $result='';
35
+ }
36
+ if(is_array($defaults) && count($defaults)>0) {
37
+ foreach($defaults as $k=>$v) {
38
+ if(count($excludes)==0 || !in_array($k, $excludes)) {
39
+ if(stripos($result, $k.'=')===FALSE) {
40
+ $result.=' '.$k.'="'.$v.'"';
41
+ }
42
+ }
43
+ }
44
+ }
45
+ return $result;
46
+ }
47
+
48
+ public function help($name) {
49
+ global $irp;
50
+ if(!$this->helps) return;
51
+
52
+ $k=$this->prefix.'.'.$name.'.Tooltip';
53
+ $label=$irp->Lang->L($k);
54
+ ?>
55
+ <img src="<?php echo IRP_PLUGIN_IMAGES.'question-mark.png'?>" class="irp-help" id="<?php echo $name?>-help" alt="<?php echo esc_attr($label)?>" />
56
+ <?php
57
+ }
58
+ public function label($name, $args='') {
59
+ global $irp;
60
+ $defaults=array('class'=>'');
61
+ $otherText=$this->getTextArgs($args, $defaults, array('label', 'id'));
62
+
63
+ $k=$this->prefix.'.'.$name;
64
+ if(!is_array($args)) {
65
+ $args=array();
66
+ }
67
+ if(isset($args['label']) && $args['label']) {
68
+ $k=$args['label'];
69
+ }
70
+ $label=$irp->Lang->L($k);
71
+ $for=(isset($args['id']) ? $args['id'] : $name);
72
+
73
+ //check if is a mandatory field by checking the .txt language file
74
+ $k=$this->prefix.'.'.$name.'.check';
75
+ if($irp->Lang->H($k)) {
76
+ $label.=' (*)';
77
+ }
78
+
79
+ $aClass='';
80
+ ?>
81
+ <label for="<?php echo $for?>" <?php echo $otherText?> >
82
+ <?php if($this->leftTags) {
83
+ $this->tag();
84
+ }?>
85
+ <span style="float:left; margin-right:5px;" class="<?php echo $aClass?>" id="<?PHP echo $for?>Label"><?php echo $label?></span>
86
+ <?php if(!$this->leftTags) {
87
+ $this->tag();
88
+ }?>
89
+ </label>
90
+ <?php }
91
+
92
+ public function leftInput($name, $args='') {
93
+ if(!$this->labels) return;
94
+
95
+ if($this->leftLabels) {
96
+ $this->help($name);
97
+ $this->label($name, $args);
98
+ }
99
+
100
+ if($this->newline) {
101
+ $this->newline();
102
+ }
103
+ }
104
+
105
+ public function newline() {
106
+ ?><div class="irp-form-newline"></div><?php
107
+ }
108
+
109
+ public function rightInput($name, $args='') {
110
+ if(!$this->labels) return;
111
+ if (!$this->leftLabels) {
112
+ $this->label($name, $args);
113
+ }
114
+ $this->newline();
115
+ }
116
+
117
+ public function formStarts($method='post', $action='', $args=NULL) {
118
+ //$defaults=array('style'=>'margin:1em 0; padding:1px 1em; background:#fff; border:1px solid #ccc;'
119
+ $defaults=array('class'=>'irp-form');
120
+ $other=$this->getTextArgs($args, $defaults);
121
+ ?>
122
+ <form method="<?php echo $method?>" action="<?php echo $action?>" <?php echo $other?> >
123
+ <?php }
124
+
125
+ public function formEnds() { ?>
126
+ </form>
127
+ <div style="clear:both;"></div>
128
+ <?php }
129
+
130
+ public function divStarts($args=array()) {
131
+ $defaults=array();
132
+ $other=$this->getTextArgs($args, $defaults);
133
+ ?>
134
+ <div <?php echo $other?>>
135
+ <?php }
136
+ public function divEnds() { ?>
137
+ </div>
138
+ <div style="clear:both;"></div>
139
+ <?php }
140
+
141
+ public function p($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
142
+ global $irp;
143
+ ?>
144
+ <p style="font-weight:bold;">
145
+ <?php
146
+ $irp->Lang->P($message, $v1, $v2, $v3, $v4, $v5);
147
+ if($irp->Lang->H($message.'Subtitle')) { ?>
148
+ <br/>
149
+ <span style="font-weight:normal;">
150
+ <i><?php $irp->Lang->P($message.'Subtitle', $v1, $v2, $v3, $v4, $v5)?></i>
151
+ </span>
152
+ <?php } ?>
153
+ </p>
154
+ <?php }
155
+
156
+ public function textarea($name, $value='', $args=NULL) {
157
+ if(is_array($value) && isset($value[$name])) {
158
+ $value=$value[$name];
159
+ }
160
+ $defaults=array('rows'=>10, 'class'=>'irp-textarea');
161
+ $other=$this->getTextArgs($args, $defaults);
162
+
163
+ $args=array('class'=>'irp-label', 'style'=>'width:auto;');
164
+ $this->newline=TRUE;
165
+ $this->leftInput($name, $args);
166
+ ?>
167
+ <textarea dir="ltr" dirname="ltr" id="<?php echo $name ?>" name="<?php echo $name?>" <?php echo $other?> ><?php echo $value ?></textarea>
168
+ <?php
169
+ $this->newline=FALSE;
170
+ $this->rightInput($name, $args);
171
+ }
172
+
173
+ public function number($name, $value='', $options=NULL) {
174
+ if(!$options) {
175
+ $options=array();
176
+ }
177
+ $options['type']='number';
178
+ $options['autocomplete']='off';
179
+ $options['style']='width:100px;';
180
+ if(!isset($options['min'])) {
181
+ $options['min']=0;
182
+ }
183
+ //if(!isset($options['step'])) {
184
+ // $options['step']=1;
185
+ //}
186
+ return $this->text($name, $value, $options);
187
+ }
188
+ public function text($name, $value='', $options=NULL) {
189
+ if(is_array($value) && isset($value[$name])) {
190
+ $value=$value[$name];
191
+ }
192
+ $type='text';
193
+ if(isset($options['type'])) {
194
+ $type=$options['type'];
195
+ }
196
+ $defaults=array('class'=>'irp-'.$type);
197
+ $other=$this->getTextArgs($options, $defaults, 'type');
198
+
199
+ $args=array('class'=>'irp-label');
200
+ $this->leftInput($name, $args);
201
+ ?>
202
+ <input type="<?php echo $type?>" id="<?php echo $name ?>" name="<?php echo $name ?>" value="<?php echo $value ?>" <?php echo $other?> />
203
+ <?php
204
+ $this->rightInput($name, $args);
205
+ }
206
+
207
+ public function hidden($name, $value='', $args=NULL) {
208
+ if(is_array($value) && isset($value[$name])) {
209
+ $value=$value[$name];
210
+ }
211
+ $defaults=array();
212
+ $other=$this->getTextArgs($args, $defaults);
213
+ ?>
214
+ <input type="hidden" id="<?php echo $name ?>" name="<?php echo $name ?>" value="<?php echo $value ?>" <?php echo $other?> />
215
+ <?php }
216
+
217
+ public function nonce($action=-1, $name='_wpnonce', $referer=true, $echo=true) {
218
+ wp_nonce_field($action, $name, $referer, $echo);
219
+ }
220
+
221
+ public function colorSelect($name, $value, $options, $multiple=FALSE, $args=NULL) {
222
+ $array=array();
223
+ foreach($options as $k=>$v) {
224
+ $color=(isset($v['color']) ? $v['color'] : '');
225
+ $fontColor=(isset($v['fontColor']) ? $v['fontColor'] : 'white');
226
+ $style='';
227
+ if($color!='') {
228
+ if($style!='') {
229
+ $style.='; ';
230
+ }
231
+ $style.='background-color:'.$color;
232
+ }
233
+ if($fontColor!='') {
234
+ if($style!='') {
235
+ $style.='; ';
236
+ }
237
+ $style.='color:'.$fontColor.'; font-weight:bold';
238
+ }
239
+ $v['id']=$color;
240
+ $v['name']=$k;
241
+ $v['style']=$style;
242
+ $array[]=$v;
243
+ }
244
+ if($args) {
245
+ $args=array();
246
+ }
247
+ $args['class']='irpColorSelect';
248
+ return $this->select($name, $value, $array, $multiple, $args);
249
+ }
250
+ public function select($name, $value, $options, $multiple=FALSE, $args=NULL) {
251
+ global $irp;
252
+ if(is_array($value) && isset($value[$name])) {
253
+ $value=$value[$name];
254
+ }
255
+ $defaults=array('class'=>'irp-select');
256
+ $other=$this->getTextArgs($args, $defaults);
257
+
258
+ if(!is_array($value)) {
259
+ $value=array($value);
260
+ }
261
+ if(is_string($options)) {
262
+ $options=explode(',', $options);
263
+ }
264
+ if(is_array($options) && count($options)>0) {
265
+ if(is_string($options[0]) || !isset($options[0][$this->selectIdField])) {
266
+ //this is a normal array so I use the values for "id" field and the "name" into the txt file
267
+ $temp=array();
268
+ foreach($options as $v) {
269
+ $item=array();
270
+ $item[$this->selectIdField]=$v;
271
+ $item['name']=$v;
272
+ if($irp->Lang->H($this->prefix.'.'.$name.'.'.$v)) {
273
+ $item['name']=$irp->Lang->L($this->prefix.'.'.$name.'.'.$v);
274
+ }
275
+ $temp[]=$item;
276
+ }
277
+ $options=$temp;
278
+ }
279
+ }
280
+
281
+ $args=array('class'=>'irp-label');
282
+ $this->leftInput($name, $args);
283
+ ?>
284
+ <select id="<?php echo $name ?>" name="<?php echo $name?><?php echo ($multiple ? '[]' : '')?>" <?php echo ($multiple ? 'multiple' : '')?> <?php echo $other?> >
285
+ <?php
286
+ foreach($options as $v) {
287
+ $style='';
288
+ if(isset($v['style'])) {
289
+ $style=$v['style'];
290
+ }
291
+
292
+ $selected='';
293
+ if(in_array($v[$this->selectIdField], $value)) {
294
+ $selected=' selected="selected"';
295
+ }
296
+ ?>
297
+ <option value="<?php echo $v[$this->selectIdField]?>" <?php echo $selected?> style="<?php echo $style?>"><?php echo $v['name']?></option>
298
+ <?php } ?>
299
+ </select>
300
+ <?php
301
+ $this->rightInput($name, $args);
302
+ }
303
+
304
+ public function submit($value='', $args=NULL) {
305
+ global $irp;
306
+ $defaults=array();
307
+ $other=$this->getTextArgs($args, $defaults);
308
+ if($value=='') {
309
+ $value='Send';
310
+ }
311
+ $this->newline();
312
+ ?>
313
+ <input type="submit" class="button-primary irp-button irp-submit" value="<?php $irp->Lang->P($value)?>" <?php echo $other?>/>
314
+ <?php }
315
+
316
+ public function delete($id, $action='delete', $args=NULL) {
317
+ global $irp;
318
+ $defaults=array();
319
+ $other=$this->getTextArgs($args, $defaults);
320
+ ?>
321
+ <input type="button" class="button irp-button" value="<?php $irp->Lang->P('Delete?')?>" onclick="if (confirm('<?php $irp->Lang->P('Are you sure you want to delete?')?>') ) window.location='<?php echo IRP_TAB_BUILDER_URI?>&action=<?php echo $action?>&id=<?php echo $id ?>&amp;irp_nonce=<?php echo esc_attr(wp_create_nonce('irp_delete')); ?>';" <?php echo $other?> />
322
+ &nbsp;
323
+ <?php
324
+ }
325
+
326
+ public function radio($name, $current=1, $value=1, $args=NULL) {
327
+ if(!is_array($args)) {
328
+ $args=array();
329
+ }
330
+ $args['radio']=TRUE;
331
+ $args['id']=$name.'_'.$value;
332
+ return $this->checkbox($name, $current, $value, $args);
333
+ }
334
+ public function checkbox($name, $current=1, $value=1, $args=NULL) {
335
+ global $irp;
336
+ if(is_array($current) && isset($current[$name])) {
337
+ $current=$current[$name];
338
+ }
339
+
340
+ /*
341
+ $defaults=array('class'=>'irp-checkbox', 'style'=>'margin:0px; margin-right:4px;');
342
+ if($this->premium && !$irp->License->hasPremium()) {
343
+ $defaults['disabled']='disabled';
344
+ $value='';
345
+ }
346
+ */
347
+ if(!is_array($args)) {
348
+ $args=array();
349
+ }
350
+
351
+ $label=$name;
352
+ $type='checkbox';
353
+ if(isset($args['radio']) && $args['radio']) {
354
+ $type='radio';
355
+ $label.='_'.$value;
356
+ }
357
+
358
+ $defaults=array(
359
+ 'class'=>'irp-checkbox'
360
+ , 'style'=>'margin:0px; margin-right:4px;'
361
+ , 'id'=>$name
362
+ );
363
+ $other=$this->getTextArgs($args, $defaults, 'radio,label,type');
364
+ $prev=$this->leftLabels;
365
+ $this->leftLabels=FALSE;
366
+
367
+ $label=(isset($args['label']) ? $args['label'] : $this->prefix.'.'.$label);
368
+ $id=(isset($args['id']) ? $args['id'] : $name);
369
+ $args=array(
370
+ 'class'=>''
371
+ , 'style'=>'margin-top:-1px;'
372
+ , 'label'=>$label
373
+ , 'id'=>$id
374
+ );
375
+ $this->leftInput($name, $args);
376
+ ?>
377
+ <input type="<?php echo $type ?>" name="<?php echo $name?>" value="<?php echo $value?>" <?php echo($current==$value ? 'checked="checked"' : '') ?> <?php echo $other?> >
378
+ <?php
379
+ $this->rightInput($name, $args);
380
+ $this->leftLabels=$prev;
381
+ }
382
+
383
+ public function checkText($nameActive, $nameText, $value) {
384
+ global $irp;
385
+
386
+ $args=array('class'=>'irp-hideShow irp-checkbox'
387
+ , 'irp-hideIfTrue'=>'false'
388
+ , 'irp-hideShow'=>$nameText.'Text');
389
+ $this->checkbox($nameActive, $value, 1, $args);
390
+ ?>
391
+ <div id="<?php echo $nameText?>Text" style="float:left;">
392
+ <?php
393
+ $prev=$this->labels;
394
+ $this->labels=FALSE;
395
+ $args=array();
396
+ $this->text($nameText, $value, $args);
397
+ $this->labels=$prev;
398
+ ?>
399
+ </div>
400
+ <?php }
401
+
402
+ //create a checkbox with a left select visible only when the checkbox is selected
403
+ public function checkSelect($nameActive, $nameArray, $value, $values) {
404
+ global $irp;
405
+ ?>
406
+ <div id="<?php echo $nameArray?>Box" style="float:left;">
407
+ <?php
408
+ $args=array('class'=>'irp-hideShow irp-checkbox'
409
+ , 'irp-hideIfTrue'=>'false'
410
+ , 'irp-hideShow'=>$nameArray.'Tags');
411
+ $this->checkbox($nameActive, $value, 1, $args);
412
+ if(TRUE) { ?>
413
+ <div id="<?php echo $nameArray?>Tags" style="float:left;">
414
+ <?php
415
+ $prev=$this->labels;
416
+ $this->labels=FALSE;
417
+ $args=array('class'=>'irp-select irpLineTags');
418
+ $this->select($nameArray, $value, $values, TRUE, $args);
419
+ $this->labels=$prev;
420
+ ?>
421
+ </div>
422
+ <?php } ?>
423
+ </div>
424
+ <?php
425
+ $this->newline();
426
+ }
427
+
428
+ public function br() { ?>
429
+ <br/>
430
+ <?php }
431
+ public function tag($overridePremium=FALSE) {
432
+ global $irp;
433
+ /*
434
+ $premium=($overridePremium || $this->premium);
435
+ if((!$overridePremium && !$this->tags) || $irp->License->hasPremium() || ($this->onlyPremium && !$premium)) return;
436
+
437
+ $tagClass='irp-tag-free';
438
+ $tagText='FREE';
439
+ if($premium) {
440
+ $tagClass='irp-tag-premium';
441
+ $tagText='<a href="'.irp_PAGE_PREMIUM.'" target="_new">PRO</a>';
442
+ }
443
+ */
444
+
445
+ if(!$this->tags || !$this->tagNew) {
446
+ return;
447
+ }
448
+
449
+ $tagClass='irp-tag-free';
450
+ $tagText='NEW!';
451
+ ?>
452
+ <div style="float:left;" class="irp-tag <?php echo $tagClass?>"><?php echo $tagText?></div>
453
+ <?php
454
+ }
455
+ }
includes/classes/ui/Tabs.php ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class IRP_Tabs {
3
+ private $tabs = array();
4
+
5
+ function init() {
6
+ global $irp;
7
+ if($irp->Utils->isAdminUser()) {
8
+ add_action('admin_menu', array(&$this, 'attachMenu'));
9
+ add_filter('plugin_action_links', array(&$this, 'pluginActions'), 10, 2);
10
+ if($irp->Utils->isPluginPage()) {
11
+ add_action('admin_enqueue_scripts', array(&$this, 'enqueueScripts'));
12
+ }
13
+ }
14
+ }
15
+
16
+ function attachMenu() {
17
+ global $irp;
18
+
19
+ if(!$irp->Plugin->isActive(IRP_PLUGINS_INTELLY_RELATED_POSTS_PRO)) {
20
+ $name='Inline Related Posts';
21
+ add_submenu_page('options-general.php'
22
+ , $name, $name
23
+ , 'manage_options', IRP_PLUGIN_SLUG, array(&$this, 'showTabPage'));
24
+ }
25
+ }
26
+ function pluginActions($links, $file) {
27
+ global $irp;
28
+ if($file==IRP_PLUGIN_SLUG.'/index.php'){
29
+ $settings = "<a href='".IRP_PAGE_SETTINGS."'>" . $irp->Lang->L('Settings') . '</a> ';
30
+ $url=IRP_INTELLYWP_SITE.IRP_PLUGIN_SLUG.'?utm_source=free-users&utm_medium=irp-plugins&utm_campaign=IRP';
31
+ $premium = "<a href='".$url."' target='_blank'>" . $irp->Lang->L('PREMIUM') . '</a> ';
32
+ $links = array_merge(array($settings, $premium), $links);
33
+ }
34
+ return $links;
35
+ }
36
+ function enqueueScripts() {
37
+ global $irp;
38
+ wp_enqueue_script('jquery');
39
+ wp_enqueue_script('suggest');
40
+ wp_enqueue_script('jquery-ui-autocomplete');
41
+
42
+ $uri='//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css';
43
+ wp_enqueue_style('font-awesome', $uri);
44
+
45
+ $this->wpEnqueueStyle('assets/css/style.css');
46
+ $this->wpEnqueueStyle('assets/deps/select2-3.5.2/select2.css');
47
+ $this->wpEnqueueScript('assets/deps/select2-3.5.2/select2.min.js');
48
+ $this->wpEnqueueScript('assets/deps/starrr/starrr.js');
49
+
50
+ $this->wpEnqueueScript('assets/deps/qtip/jquery.qtip.min.js');
51
+ $this->wpEnqueueScript('assets/js/common.js');
52
+ }
53
+ function wpEnqueueStyle($uri, $name='') {
54
+ if($name=='') {
55
+ $name=explode('/', $uri);
56
+ $name=$name[count($name)-1];
57
+ $dot=strrpos($name, '.');
58
+ if($dot!==FALSE) {
59
+ $name=substr($name, 0, $dot);
60
+ }
61
+ $name=IRP_PLUGIN_PREFIX.'_'.$name;
62
+ }
63
+
64
+ $v='?v='.IRP_PLUGIN_VERSION;
65
+ wp_enqueue_style($name, IRP_PLUGIN_URI.$uri.$v);
66
+ }
67
+ function wpEnqueueScript($uri, $name='', $version=FALSE) {
68
+ if($name=='') {
69
+ $name=explode('/', $uri);
70
+ $name=$name[count($name)-1];
71
+ $dot=strrpos($name, '.');
72
+ if($dot!==FALSE) {
73
+ $name=substr($name, 0, $dot);
74
+ }
75
+ $name=IRP_PLUGIN_PREFIX.'_'.$name;
76
+ }
77
+
78
+ $v='?v='.IRP_PLUGIN_VERSION;
79
+ $deps=array();
80
+ wp_enqueue_script($name, IRP_PLUGIN_URI.$uri.$v, $deps, $version, FALSE);
81
+ }
82
+
83
+ function showTabPage() {
84
+ global $irp;
85
+
86
+ if($irp->Plugin->isActive(IRP_PLUGINS_INTELLY_RELATED_POSTS_PRO)) {
87
+ $irp->Options->pushWarningMessage('YouHaveThePremiumVersion', IRP_TAB_SETTINGS_URI);
88
+ $irp->Options->writeMessages();
89
+ return;
90
+ }
91
+
92
+ $defaultTab=IRP_TAB_SETTINGS;
93
+ if($irp->Options->isShowWhatsNew()) {
94
+ $tab=IRP_TAB_WHATS_NEW;
95
+ $defaultTab=$tab;
96
+ $this->tabs[IRP_TAB_WHATS_NEW]=$irp->Lang->L('What\'s New');
97
+ } else {
98
+ $tab = $irp->Utils->qs('tab', $defaultTab);
99
+ $this->tabs[IRP_TAB_SETTINGS] = $irp->Lang->L('Settings');
100
+ $this->tabs[IRP_TAB_DOCS] = $irp->Lang->L('FAQ & Docs');
101
+ }
102
+
103
+ ?>
104
+ <div class="wrap" style="margin:5px;">
105
+ <?php
106
+ $this->showTabs($defaultTab);
107
+ $header='';
108
+ switch ($tab) {
109
+ case IRP_TAB_SETTINGS:
110
+ $header='Settings';
111
+ break;
112
+ case IRP_TAB_WHATS_NEW:
113
+ $header='';
114
+ break;
115
+ }
116
+
117
+ if($irp->Lang->H($header.'Title')) { ?>
118
+ <h2><?php $irp->Lang->P($header . 'Title', IRP_PLUGIN_VERSION) ?></h2>
119
+ <?php if ($irp->Lang->H($header . 'Subtitle')) { ?>
120
+ <div><?php $irp->Lang->P($header . 'Subtitle') ?></div>
121
+ <?php } ?>
122
+ <div style="clear:both;"></div>
123
+ <?php }
124
+
125
+ if($tab!=IRP_TAB_WHATS_NEW) {
126
+ irp_ui_first_time();
127
+ }
128
+
129
+ switch ($tab) {
130
+ case IRP_TAB_SETTINGS:
131
+ irp_ui_settings();
132
+ break;
133
+ case IRP_TAB_WHATS_NEW:
134
+ irp_ui_whats_new();
135
+ break;
136
+ }
137
+
138
+ if($irp->Options->isShowWhatsNew()) {
139
+ $irp->Options->setShowWhatsNew(FALSE);
140
+ }
141
+ ?>
142
+ </div>
143
+ <?php }
144
+
145
+ function showTabs($defaultTab) {
146
+ global $irp;
147
+ $tab=$irp->Check->of('tab', $defaultTab);
148
+ if($tab==IRP_TAB_DOCS) {
149
+ $irp->Utils->redirect(IRP_TAB_DOCS_URI);
150
+ }
151
+
152
+ ?>
153
+ <h2 class="nav-tab-wrapper" style="float:left; width:97%;">
154
+ <?php
155
+ foreach ($this->tabs as $k=>$v) {
156
+ $active = ($tab==$k ? 'nav-tab-active' : '');
157
+ ?>
158
+ <a style="float:left; margin-left:10px;" class="nav-tab <?php echo $active?>" href="?page=<?php echo IRP_PLUGIN_SLUG?>&tab=<?php echo $k?>"><?php echo $v?></a>
159
+ <?php
160
+ }
161
+ ?>
162
+ <style>
163
+ .starrr {display:inline-block}
164
+ .starrr i{font-size:16px;padding:0 1px;cursor:pointer;color:#2ea2cc;}
165
+ </style>
166
+ <div style="float:right; display:none;" id="rate-box">
167
+ <span style="font-weight:700; font-size:13px; color:#555;"><?php $irp->Lang->P('Rate us')?></span>
168
+ <div id="irp-rate" class="starrr" data-connected-input="irp-rate-rank"></div>
169
+ <input type="hidden" id="irp-rate-rank" name="irp-rate-rank" value="5" />
170
+ <?php $irp->Utils->twitter('intellywp') ?>
171
+ </div>
172
+ <script>
173
+ jQuery(function() {
174
+ jQuery(".starrr").starrr();
175
+ jQuery('#irp-rate').on('starrr:change', function(e, value){
176
+ var url='https://wordpress.org/support/view/plugin-reviews/<?php echo IRP_PLUGIN_SLUG?>?rate=5#postform';
177
+ window.open(url);
178
+ });
179
+ jQuery('#rate-box').show();
180
+ });
181
+ </script>
182
+ </h2>
183
+ <div style="clear:both;"></div>
184
+ <?php }
185
+ }
includes/classes/utils/AppOptions.php ADDED
@@ -0,0 +1,422 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class IRP_AppOptions extends IRP_Options {
4
+ public function __construct() {
5
+ }
6
+
7
+ public function getMarginTop() {
8
+ return $this->getOption('MarginTop', '0em');
9
+ }
10
+ public function setMarginTop($value) {
11
+ $this->setOption('MarginTop', $value);
12
+ }
13
+ public function getMarginBottom() {
14
+ return $this->getOption('MarginBottom', '1em');
15
+ }
16
+ public function setMarginBottom($value) {
17
+ $this->setOption('MarginBottom', $value);
18
+ }
19
+
20
+ public function hasRelatedPostsIds() {
21
+ $array=$this->getRequest('RelatedPostsIds', array());
22
+ return (is_array($array) && count($array)>0);
23
+ }
24
+ public function initRelatedPostsIds($ids) {
25
+ $this->setRequest('RelatedPostsIds', $ids);
26
+ if($ids) {
27
+ shuffle($ids);
28
+ }
29
+ $this->setRequest('ToShowPostsIds', $ids);
30
+ $this->setRequest('ShownPostsIdsSequence', array());
31
+ $this->setRewriteBoxesWritten(0);
32
+ }
33
+ public function refreshRelatedPostsIds() {
34
+ $ids=$this->getRequest('RelatedPostsIds', array());
35
+ $this->initRelatedPostsIds($ids);
36
+ }
37
+ //if you pass maxIds as a number this function take next [maxIds] posts to show as related
38
+ //if you pass maxIds as an array of postsIds will return this array as posts to show as related
39
+ public function getToShowPostsIds($maxIds, $repeat=FALSE) {
40
+ $result=array();
41
+ $maxIds=intval($maxIds);
42
+ if(!$this->hasRelatedPostsIds()) {
43
+ return $result;
44
+ }
45
+
46
+ $toShow=$this->getRequest('ToShowPostsIds', array());
47
+ if(is_numeric($maxIds)) {
48
+ if(!is_array($toShow) || (count($toShow)==0 && !$repeat)) {
49
+ return $result;
50
+ }
51
+ while($maxIds>0) {
52
+ if(count($toShow)==0) {
53
+ if($repeat) {
54
+ //i can use again the posts shown
55
+ $toShow=$this->getRequest('RelatedPostsIds');
56
+ shuffle($toShow);
57
+ } else {
58
+ break;
59
+ }
60
+ }
61
+
62
+ $postId=array_pop($toShow);
63
+ $result[]=$postId;
64
+ --$maxIds;
65
+ }
66
+ } elseif(is_array($maxIds)) {
67
+ $toShow=array_diff($toShow, $maxIds);
68
+ $result=$maxIds;
69
+ }
70
+ $this->setRequest('ToShowPostsIds', $toShow);
71
+
72
+ //update the sequence shown
73
+ $array=$this->getRequest('ShownPostsIdsSequence', array());
74
+ $array[]=$result;
75
+ $this->setRequest('ShownPostsIdsSequence', $array);
76
+
77
+ return $result;
78
+ }
79
+ public function getShownPostsIdsSequence() {
80
+ return $this->getRequest('ShownPostsIdsSequence', array());
81
+ }
82
+
83
+ public function getPostShown() {
84
+ return $this->getRequest('PostShown', NULL);
85
+ }
86
+ public function setPostShown($value) {
87
+ $this->setRequest('PostShown', $value);
88
+ }
89
+ public function isPostShownExcluded() {
90
+ global $irp;
91
+ $array=$this->getExcludedPostsIds();
92
+ $post=$this->getPostShown();
93
+
94
+ $result=FALSE;
95
+ if(!$post || !isset($post->ID)) {
96
+ $result=TRUE;
97
+ } elseif(in_array($post->ID, $array)) {
98
+ $irp->Log->info('POST ID=%s IN RELATED POSTS EXCLUDE LIST', $post->ID);
99
+ $result=TRUE;
100
+ } else {
101
+ $result=FALSE;
102
+ }
103
+ return $result;
104
+ }
105
+ public function isShortcodeUsed() {
106
+ return $this->getRequest('ShortcodeUsed', 0);
107
+ }
108
+ public function setShortcodeUsed($value) {
109
+ $this->setRequest('ShortcodeUsed', $value);
110
+ }
111
+
112
+ public function getTemplateStyle() {
113
+ global $irp;
114
+
115
+ $defaults=array(
116
+ 'template'=>''
117
+ , 'linkRel'=>$this->getOption('LinkRel', 'nofollow')
118
+ , 'linkTarget'=>$this->getOption('LinkTarget', '_blank')
119
+ , 'ctaText'=>$this->getOption('RelatedText', 'READ')
120
+ , 'ctaTextColor'=>$this->getOption('TemplateRelatedTextColor', '')
121
+ , 'postTitleColor'=>$this->getOption('TemplateRelatedTextColor', '')
122
+ , 'boxColor'=>$this->getOption('TemplateBackgroundColor', '')
123
+ , 'borderColor'=>$this->getOption('TemplateBorderColor', '')
124
+ , 'hasShadow'=>$this->getOption('TemplateShadow', FALSE)
125
+ , 'hasPoweredBy'=>$this->getOption('ShowPoweredBy', FALSE)
126
+ , 'boxOpacity'=>100
127
+ );
128
+ $result=$this->getOption('TemplateStyle', $defaults);
129
+ $names=$irp->HtmlTemplate->getTemplatesNames();
130
+ if($result['template']=='' || !in_array($result['template'], $names)) {
131
+ if(count($names)>0) {
132
+ $result['template']='Minimalist';//$names[0];
133
+ }
134
+ }
135
+ return $result;
136
+ }
137
+ public function setTemplateStyle($value) {
138
+ $this->setOption('TemplateStyle', $value);
139
+ }
140
+
141
+ //is related posts active in posts without any [irl] shortcodes defined
142
+ public function isRewriteActive() {
143
+ return $this->getOption('RewriteActive', 1);
144
+ }
145
+ public function setRewriteActive($value) {
146
+ $this->setOption('RewriteActive', $value);
147
+ }
148
+ public function getExcludedPostsIds() {
149
+ return $this->getOption('ExcludedPostsIds', array());
150
+ }
151
+ public function setExcludedPostsIds($value) {
152
+ $value=array_unique($value);
153
+ $this->setOption('ExcludedPostsIds', $value);
154
+ }
155
+ public function getMetaboxPostTypes($create=TRUE) {
156
+ global $irp;
157
+ $result=$this->getOption('MetaboxPostTypes', array());
158
+ if($create) {
159
+ $types=$irp->Utils->query(IRP_QUERY_POST_TYPES);
160
+ foreach($types as $v) {
161
+ $v=$v['id'];
162
+ if(!isset($result[$v])) {
163
+ $result[$v]=($v=='post' ? 1 : 0);
164
+ }
165
+ }
166
+ }
167
+ return $result;
168
+ }
169
+ public function setMetaboxPostTypes($values) {
170
+ $this->setOption('MetaboxPostTypes', $values);
171
+ }
172
+ //is integrated with which post types?
173
+ public function getRewritePostTypes($create=TRUE) {
174
+ global $irp;
175
+ $result=$this->getOption('RewritePostTypes', array());
176
+ if($create) {
177
+ $types=$irp->Utils->query(IRP_QUERY_POST_TYPES);
178
+ foreach($types as $v) {
179
+ $v=$v['id'];
180
+ if(!isset($result[$v])) {
181
+ $result[$v]=($v=='post' ? 1 : 0);
182
+ }
183
+ }
184
+ }
185
+ return $result;
186
+ }
187
+ public function setRewritePostTypes($values) {
188
+ $this->setOption('RewritePostTypes', $values);
189
+ }
190
+ //how many related posts boxes we have to include?
191
+ public function getRewriteBoxesCount() {
192
+ return intval($this->getOption('RewriteBoxesCount', 3));
193
+ }
194
+ public function setRewriteBoxesCount($value) {
195
+ $this->setOption('RewriteBoxesCount', $value);
196
+ }
197
+ //how many related posts we see in each box?
198
+ public function getRewritePostsInBoxCount() {
199
+ //return $this->getOption('RewritePostsInBoxCount', 1);
200
+ return 1;
201
+ }
202
+ public function setRewritePostsInBoxCount($value) {
203
+ $this->setOption('RewritePostsInBoxCount', $value);
204
+ }
205
+ public function getRewritePostsDays() {
206
+ return intval($this->getOption('RewritePostsDays', 0));
207
+ }
208
+ public function setRewritePostsDays($value) {
209
+ $this->setOption('RewritePostsDays', intval($value));
210
+ }
211
+ //how many words we have to "wait" before inserting a related box
212
+ public function getRewriteThreshold() {
213
+ return $this->getOption('RewriteThreshold', 250);
214
+ }
215
+ public function setRewriteThreshold($value) {
216
+ $this->setOption('RewriteThreshold', $value);
217
+ }
218
+ //include also a related box in the end?
219
+ public function isRewriteAtEnd() {
220
+ return $this->getOption('RewriteAtEnd', TRUE);
221
+ }
222
+ public function setRewriteAtEnd($value) {
223
+ $this->setOption('RewriteAtEnd', $value);
224
+ }
225
+ //how many boxes are already been written?
226
+ public function getRewriteBoxesWritten() {
227
+ return $this->getRequest('RewriteBoxesWritten', 0);
228
+ }
229
+ public function setRewriteBoxesWritten($value) {
230
+ $this->setRequest('RewriteBoxesWritten', $value);
231
+ }
232
+
233
+ public function getEngineSearch() {
234
+ return $this->getOption('EngineSearch', IRP_ENGINE_SEARCH_CATEGORIES_TAGS);
235
+ }
236
+ public function setEngineSearch($value) {
237
+ $this->setOption('EngineSearch', $value);
238
+ }
239
+
240
+ public function getMaxExecutionTime(){
241
+ return $this->getOption('MaxExecutionTime', -1);
242
+ }
243
+ public function resetMaxExecutionTime(){
244
+ $this->setOption('MaxExecutionTime', -1);
245
+ }
246
+ public function updateMaxExecutionTime($value){
247
+ $now=$this->getMaxExecutionTime();
248
+ if($value>$now) {
249
+ $this->setOption('MaxExecutionTime', $value);
250
+ }
251
+ }
252
+
253
+ public function pushCssStyle($code) {
254
+ global $irp;
255
+ if(is_array($code)) {
256
+ $code=implode("\n", $code);
257
+ }
258
+ $code=str_replace('<style>', '', $code);
259
+ $code=str_replace('</style>', '', $code);
260
+ $code=$irp->Utils->trimCode($code);
261
+
262
+ $array=$this->getCssStyles();
263
+ $exists=FALSE;
264
+ if(count($array)>0) {
265
+ foreach($array as $v) {
266
+ if(trim($v)==trim($code)) {
267
+ $exists=TRUE;
268
+ break;
269
+ }
270
+ }
271
+ }
272
+ if(!$exists) {
273
+ $array[]=$code;
274
+ $this->setRequest('CssStyles', $array);
275
+ }
276
+ }
277
+ public function getCssStyles() {
278
+ return $this->getRequest('CssStyles', array());
279
+ }
280
+
281
+ public function getColor($color) {
282
+ global $irp;
283
+ $result=$color;
284
+ if(!$irp->Utils->startsWith($color, '#')) {
285
+ $colors=$this->getLegacyColors();
286
+ $v=$irp->Utils->geti($colors, $color, FALSE);
287
+ if($v!==FALSE) {
288
+ $result=$v['color'];
289
+ } else {
290
+ $colors=$this->getColors();
291
+ $v=$irp->Utils->geti($colors, $color, FALSE);
292
+ if($v!==FALSE) {
293
+ $result=$v['color'];
294
+ }
295
+ }
296
+ }
297
+ return $result;
298
+ }
299
+ public function getHoverColor($color) {
300
+ $color=$this->getColor($color);
301
+ $colors=$this->getLightDarkColors();
302
+ $result='';
303
+ foreach($colors as $k=>$v) {
304
+ if($v['light']==$color) {
305
+ $result=$v['dark'];
306
+ break;
307
+ } elseif($v['dark']==$color) {
308
+ $result=$v['light'];
309
+ break;
310
+ }
311
+ }
312
+ return $result;
313
+ }
314
+ public function getColors($blank='') {
315
+ $array=$this->getLightDarkColors();
316
+ $result=array();
317
+ if($blank!='') {
318
+ $result[$blank]=array('color'=>'', 'fontColor'=>'#464646');
319
+ }
320
+ foreach($array as $k=>$v) {
321
+ if(isset($v['color'])) {
322
+ $a=array();
323
+ $a['color']=$v['color'];
324
+ if(isset($v['fontColor'])) {
325
+ $a['fontColor']=$v['fontColor'];
326
+ }
327
+ $result[$k]=$a;
328
+ }
329
+ if(isset($v['light'])) {
330
+ $a=array();
331
+ $a['color']=$v['light'];
332
+ if(isset($v['fontLight'])) {
333
+ $a['fontColor']=$v['fontLight'];
334
+ }
335
+ $result[$k.' Light']=$a;
336
+ }
337
+ if(isset($v['dark'])) {
338
+ $a=array();
339
+ $a['color']=$v['dark'];
340
+ if(isset($v['fontDark'])) {
341
+ $a['fontColor']=$v['fontDark'];
342
+ }
343
+ $result[$k.' Dark']=$a;
344
+ }
345
+ }
346
+
347
+ ksort($result);
348
+ return $result;
349
+ }
350
+ //$colors['(Default)']=array('color'=>'', 'fontColor'=>'#464646');
351
+ public function getLightDarkColors() {
352
+ $colors['WHITE']=array(
353
+ 'light'=>'#FFFFFF', 'fontLight'=>'#464646'
354
+ , 'dark'=>'#eaeaea', 'fontDark'=>'#464646'
355
+ );
356
+ $colors['AQUA']=array('light'=>'#1ABC9C', 'dark'=>'#16A085');
357
+ $colors['GREEN']=array('light'=>'#2ECC71', 'dark'=>'#27AE60');
358
+ $colors['VIOLET']=array('light'=>'#9B59B6', 'dark'=>'#8E44AD');
359
+ $colors['BLUE #1']=array('light'=>'#3498DB', 'dark'=>'#2980B9');
360
+ $colors['BLUE #2']=array('light'=>'#34495E', 'dark'=>'#2C3E50');
361
+ $colors['YELLOW']=array('light'=>'#F1C40F', 'dark'=>'#F39C12');
362
+ $colors['ORANGE']=array('light'=>'#E67E22', 'dark'=>'#D35400');
363
+ $colors['RED']=array('light'=>'#E74C3C', 'dark'=>'#C0392B');
364
+ $colors['GREY #1']=array(
365
+ 'light'=>'#ECF0F1', 'fontLight'=>'#464646'
366
+ , 'dark'=>'#e6e6e6', 'fontDark'=>'#464646'
367
+ );
368
+ $colors['GREY #2']=array('light'=>'#95A5A6', 'dark'=>'#7F8C8D');
369
+ $colors['BLACK']=array('light'=>'#141414', 'dark'=>'#000000');
370
+ ksort($colors);
371
+ return $colors;
372
+ }
373
+ public function getLegacyColors() {
374
+ $colors=array();
375
+ $colors['(Default)']=array('color'=>'', 'fontColor'=>'#464646');
376
+ $colors['WHITE']=array('color'=>'#FFFFFF', 'fontColor'=>'#464646');
377
+ $colors['LIGHT GREY']=array('color'=>'#ECF0F1', 'fontColor'=>'#464646');
378
+ $colors['DARK GREY']=array('color'=>'#555555');
379
+ $colors['BLACK']=array('color'=>'#000000');
380
+
381
+ $colors['(Transparent)']=array('color'=>'', 'fontColor'=>'#464646');
382
+ $colors['WHITE']=array('color'=>'#FFFFFF', 'fontColor'=>'#464646');
383
+ $colors['LIGHT GREY']=array('color'=>'#ECF0F1', 'fontColor'=>'#464646');
384
+ $colors['DARK GREY']=array('color'=>'#555555');
385
+ $colors['BLACK']=array('color'=>'#000000'); //black
386
+
387
+ $colors['(Transparent)']=array('color'=>'', 'fontColor'=>'#464646');
388
+ $colors['TURQUOISE']=array('color'=>'#1ABC9C'); //Aqua
389
+ $colors['EMERALD']=array('color'=>'#2ECC71'); //green
390
+ $colors['AMETHYST']=array('color'=>'#9B59B6');//violet
391
+ $colors['PETER RIVER']=array('color'=>'#3498DB');//blue
392
+ $colors['WET ASPHALT']=array('color'=>'#34495E');//blue
393
+ $colors['SUN FLOWER']=array('color'=>'#F1C40F');//yellow
394
+ $colors['CARROT']=array('color'=>'#E67E22');//orange
395
+ $colors['ALIZARIN']=array('color'=>'#E74C3C');//red
396
+ $colors['CLOUDS']=array('color'=>'#ECF0F1', 'fontColor'=>'#464646');//grey
397
+ $colors['CONCRETE']=array('color'=>'#95A5A6');//grey (+grey)
398
+
399
+ $colors['(Transparent)']=array('color'=>'', 'fontColor'=>'#464646');
400
+ $colors['GREEN SEA']=array('color'=>'#16A085');
401
+ $colors['NEPHRITIS']=array('color'=>'#27AE60');
402
+ $colors['WISTERIA']=array('color'=>'#8E44AD');
403
+ $colors['BELIZE HOLE']=array('color'=>'#2980B9');
404
+ $colors['MIDNIGHT BLUE']=array('color'=>'#2C3E50');
405
+ $colors['ORANGE']=array('color'=>'#F39C12');
406
+ $colors['PUMPKIN']=array('color'=>'#D35400');
407
+ $colors['POMEGRANATE']=array('color'=>'#C0392B');
408
+ $colors['SILVER']=array('color'=>'#BDC3C7');
409
+ $colors['ASBESTOS']=array('color'=>'#7F8C8D');
410
+ ksort($colors);
411
+ return $colors;
412
+ }
413
+
414
+ public function getTemplateUUID($template) {
415
+ $uuid=$this->getRequest("Template>".$template);
416
+ if(!$uuid) {
417
+ $uuid="s".md5($template."-".date("Ymd"));
418
+ $this->setRequest("Template>".$template, $uuid);
419
+ }
420
+ return $uuid;
421
+ }
422
+ }
includes/classes/utils/Cron.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 IRP_Cron {
16
+ /**
17
+ * Get things going
18
+ *
19
+ * @since 1.6
20
+ * @see EDD_Cron::weekly_events()
21
+ */
22
+ public function __construct() {
23
+ }
24
+ public function init() {
25
+ add_filter( 'cron_schedules', array( $this, 'add_schedules' ) );
26
+ add_action( 'wp', array( $this, 'schedule_Events' ) );
27
+ }
28
+
29
+ /**
30
+ * Registers new cron schedules
31
+ *
32
+ * @since 1.6
33
+ *
34
+ * @param array $schedules
35
+ * @return array
36
+ */
37
+ public function add_schedules( $schedules = array() ) {
38
+ global $irp;
39
+ // Adds once weekly to the existing schedules.
40
+ $schedules['weekly'] = array(
41
+ 'interval' => 604800,
42
+ 'display' => $irp->Lang->L('Once Weekly')
43
+ );
44
+
45
+ return $schedules;
46
+ }
47
+
48
+ /**
49
+ * Schedules our events
50
+ *
51
+ * @access public
52
+ * @since 1.6
53
+ * @return void
54
+ */
55
+ public function schedule_Events() {
56
+ $this->weekly_events();
57
+ $this->daily_events();
58
+ }
59
+
60
+ /**
61
+ * Schedule weekly events
62
+ *
63
+ * @access private
64
+ * @since 1.6
65
+ * @return void
66
+ */
67
+ private function weekly_events() {
68
+ if ( ! wp_next_scheduled( 'irp_weekly_scheduled_events' ) ) {
69
+ wp_schedule_event( current_time( 'timestamp' ), 'weekly', 'irp_weekly_scheduled_events' );
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Schedule daily events
75
+ *
76
+ * @access private
77
+ * @since 1.6
78
+ * @return void
79
+ */
80
+ private function daily_events() {
81
+ if ( ! wp_next_scheduled( 'irp_daily_scheduled_events' ) ) {
82
+ wp_schedule_event( current_time( 'timestamp' ), 'daily', 'irp_daily_scheduled_events' );
83
+ }
84
+ }
85
+ }
includes/classes/utils/Language.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ class IRP_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
+ $s=strpos($result, '_');
53
+ if ($s!==FALSE) {
54
+ $text = substr($result, 0, $s);
55
+ $value = substr($result, $s + 1);
56
+ $e = strrpos($value, '_');
57
+ if ($e!==FALSE) {
58
+ $text .= substr($value, $e + 1);
59
+ $value = substr($value, 0, $e);
60
+ }
61
+ if (isset($bundle[$text])) {
62
+ $result = TRUE;
63
+ }
64
+ }
65
+ }
66
+ return $result;
67
+ }
68
+ //read the key from a text file with its translation. Try to translate using __(
69
+ function L($key, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
70
+ global $wp_session;
71
+ $bundle=$wp_session['LanguageBundle_'.$this->domain];
72
+ $result = $key;
73
+ $args = array($v1, $v2, $v3, $v4, $v5);
74
+
75
+ if($bundle==NULL || count($bundle)==0) {
76
+ $result=__($result, $this->domain);
77
+ } else {
78
+ //i use the file to store the translations without writing it inside the code
79
+ if (isset($bundle[$key])) {
80
+ $result = $bundle[$key];
81
+ $result = __($result, $this->domain);
82
+ } elseif (isset($bundle[$key . '1'])) {
83
+ $result = '';
84
+ $n = 1;
85
+ while (isset($bundle[$key . $n])) {
86
+ if ($result != '') {
87
+ $result .= '<br/>';
88
+ }
89
+ $result .= __($bundle[$key . $n], $this->domain);
90
+ ++$n;
91
+ }
92
+ } else {
93
+ //special way to call this function passing arguments
94
+ //WTF_something means key=WTF and something as first argument
95
+ $s=strpos($result, '_');
96
+ if ($s!==FALSE) {
97
+ $text = substr($result, 0, $s);
98
+ $value = substr($result, $s + 1);
99
+ $e = strrpos($value, '_');
100
+ if ($e!==FALSE) {
101
+ $text .= substr($value, $e + 1);
102
+ $value = substr($value, 0, $e);
103
+ }
104
+ if (isset($bundle[$text])) {
105
+ $result = $bundle[$text];
106
+ $args=array($value);
107
+ }
108
+ }
109
+ $result = __($result, $this->domain);
110
+ }
111
+ }
112
+ //here i translate it using WP
113
+ foreach($args as $k=>$v) {
114
+ $k='{'.$k.'}';
115
+ while(strpos($result, $k)!==FALSE) {
116
+ $result=str_replace($k, $v, $result);
117
+ }
118
+ }
119
+ return $result;
120
+ }
121
+ }
includes/classes/utils/Logger.php ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Exit if accessed directly
4
+ if ( ! defined( 'ABSPATH' ) ) exit;
5
+
6
+ class IRP_Logger {
7
+ var $name;
8
+ var $context=array();
9
+
10
+ var $allTime;
11
+ var $time;
12
+ var $profile;
13
+
14
+ public function __construct($name='IRPP') {
15
+ if($name=='') $name='IRPP';
16
+ $this->name=$name;
17
+ $this->time=-1;
18
+ $this->allTime=-1;
19
+ $this->profile='';
20
+ }
21
+
22
+ public function startTime($profile) {
23
+ $this->info('TIME [startTime]=%s', $profile);
24
+ $this->profile=$profile;
25
+ $this->time=microtime(TRUE);
26
+ }
27
+ public function pauseTime() {
28
+ if($this->time>0 && $this->profile!='') {
29
+ $diff=round(microtime(TRUE)-$this->time, 3)*1000;
30
+ if($diff!='' && $diff>0) {
31
+ if($this->allTime<0) {
32
+ $this->allTime=0;
33
+ }
34
+ $this->allTime+=$diff;
35
+ $this->info('TIME pauseTime [%s]=%s', $this->profile, $diff);
36
+ }
37
+ }
38
+ $this->time=-1;
39
+ $this->profile='';
40
+ }
41
+ public function stopTime() {
42
+ global $irp;
43
+ $this->info('TIME [stopTime]=%s', $this->allTime);
44
+ if($this->allTime>0) {
45
+ $irp->Options->updateMaxExecutionTime($this->allTime);
46
+ }
47
+ }
48
+
49
+ public function pushContext($context) {
50
+ array_push($this->context, $context);
51
+ }
52
+ public function popContext() {
53
+ array_pop($this->context);
54
+ }
55
+
56
+ public function exception(Exception $ex) {
57
+ $this->write('[EXCEPTION]', 'FILE=%s, LINE=%s, CODE=%s, MESSAGE=%s'
58
+ , $ex->getFile(), $ex->getLine(), $ex->getCode(), $ex->getMessage());
59
+ }
60
+ public function fatal($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL, $v6=NULL) {
61
+ $what=$this->write('[FATAL]', $message, $v1, $v2, $v3, $v4, $v5, $v6);
62
+ die($what);
63
+ }
64
+ public function debug($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL, $v6=NULL) {
65
+ $this->write('[DEBUG]', $message, $v1, $v2, $v3, $v4, $v5, $v6);
66
+ }
67
+ public function info($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL, $v6=NULL) {
68
+ $this->write('[INFO] ', $message, $v1, $v2, $v3, $v4, $v5, $v6);
69
+ }
70
+ public function error($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL, $v6=NULL) {
71
+ $this->write('[ERROR]', $message, $v1, $v2, $v3, $v4, $v5, $v6);
72
+ }
73
+ private function dump($v) {
74
+ if(is_array($v) && count($v)==0) {
75
+ $v='[]';
76
+ }
77
+ if($v!=NULL) {
78
+ if(is_array($v) || is_object($v)) {
79
+ $v=print_r($v, TRUE);
80
+ }
81
+ }
82
+ if(is_bool($v)) {
83
+ $v=($v ? 'TRUE' : 'FALSE');
84
+ }
85
+ return $v;
86
+ }
87
+ private function write($verbosity, $message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL, $v6=NULL) {
88
+ global $irp;
89
+
90
+ $text=sprintf($message
91
+ , $this->dump($v1), $this->dump($v2), $this->dump($v3)
92
+ , $this->dump($v4), $this->dump($v5), $this->dump($v6));
93
+ $m=microtime(TRUE)%1000;
94
+ $m=":".str_pad(''.$m, 3, "0", STR_PAD_LEFT);
95
+ $message=date("d/m/Y H:i:s").$m." ".$verbosity." ";
96
+ if(count($this->context)>0) {
97
+ $message.='{'.$this->context[count($this->context)-1].'} ';
98
+ }
99
+ $message="\n".$message.$text;
100
+ if(!$irp->Options->isLoggerEnable()) {
101
+ return $message;
102
+ }
103
+
104
+ $hasErrors=false;
105
+ $filename=IRP_PLUGIN_ROOT."logs/".$this->name."_".date("Ym").".txt";
106
+ if (!$handle = fopen($filename, 'a')) {
107
+ $hasErrors=true;
108
+ }
109
+
110
+ if(!$hasErrors && fwrite($handle, $message)===FALSE) {
111
+ $hasErrors=true;
112
+ }
113
+
114
+ if(!$hasErrors) {
115
+ fclose($handle);
116
+ }
117
+ return $message;
118
+ }
119
+ }
includes/classes/utils/Options.php ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Exit if accessed directly
4
+ if ( ! defined( 'ABSPATH' ) ) exit;
5
+
6
+ class IRP_Options {
7
+ var $vars;
8
+ public function __construct() {
9
+ $this->vars=array();
10
+ }
11
+
12
+ //always add a prefix to avoid conflicts with other plugins
13
+ protected function getKey($key) {
14
+ return 'IRP_'.$key;
15
+ }
16
+ //option
17
+ protected function removeOption($key) {
18
+ $key=$this->getKey($key);
19
+ delete_option($key);
20
+ }
21
+ protected function getOption($key, $default=FALSE) {
22
+ $key=$this->getKey($key);
23
+ $result=get_option($key, $default);
24
+ if(is_string($result)) {
25
+ $result=trim($result);
26
+ }
27
+ return $result;
28
+ }
29
+ protected function setOption($key, $value) {
30
+ $key=$this->getKey($key);
31
+ if(is_bool($value)) {
32
+ $value=($value ? 1 : 0);
33
+ }
34
+ update_option($key, $value);
35
+ }
36
+
37
+ //$_SESSION
38
+ protected function removeSession($key) {
39
+ global $wp_session;
40
+
41
+ $key=$this->getKey($key);
42
+ if(isset($wp_session[$key])) {
43
+ unset($wp_session[$key]);
44
+ }
45
+ }
46
+ protected function getSession($key, $default=FALSE) {
47
+ global $wp_session;
48
+
49
+ $key=$this->getKey($key);
50
+ $result=$default;
51
+ if(isset($wp_session[$key])) {
52
+ $result=$wp_session[$key];
53
+ }
54
+ if(is_string($result)) {
55
+ $result=trim($result);
56
+ }
57
+ return $result;
58
+ }
59
+ protected function setSession($key, $value) {
60
+ global $wp_session;
61
+
62
+ $key=$this->getKey($key);
63
+ $wp_session[$key]=$value;
64
+ }
65
+
66
+ //$_REQUEST
67
+ //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.
68
+ protected function removeRequest($key) {
69
+ $key=$this->getKey($key);
70
+ if(isset($this->vars[$key])) {
71
+ unset($this->vars[$key]);
72
+ }
73
+ }
74
+ protected function getRequest($key, $default=FALSE) {
75
+ $key=$this->getKey($key);
76
+ $result=$default;
77
+ if(isset($this->vars[$key])) {
78
+ $result=$this->vars[$key];
79
+ }
80
+ return $result;
81
+ }
82
+ protected function setRequest($key, $value) {
83
+ $key=$this->getKey($key);
84
+ $this->vars[$key]=$value;
85
+ }
86
+
87
+ //ShowWhatsNew
88
+ public function isShowWhatsNew() {
89
+ return $this->getOption('ShowWhatsNew', FALSE);
90
+ }
91
+ public function setShowWhatsNew($value) {
92
+ $this->setOption('ShowWhatsNew', $value);
93
+ }
94
+
95
+ //TrackingEnable
96
+ public function isTrackingEnable() {
97
+ return $this->getOption('TrackingEnable', 0);
98
+ }
99
+ public function setTrackingEnable($value) {
100
+ $this->setOption('TrackingEnable', $value);
101
+ }
102
+ //TrackingNotice
103
+ public function isTrackingNotice() {
104
+ return $this->getOption('TrackingNotice', 1);
105
+ }
106
+ public function setTrackingNotice($value) {
107
+ $this->setOption('TrackingNotice', $value);
108
+ }
109
+
110
+ public function isActive() {
111
+ return $this->getOption('Active', 0);
112
+ }
113
+ public function setActive($value) {
114
+ $this->setOption('Active', $value);
115
+ }
116
+
117
+ public function getTrackingLastSend() {
118
+ return $this->getOption('TrackingLastSend['.IRP_PLUGIN_SLUG.']', 0);
119
+ }
120
+ public function setTrackingLastSend($value) {
121
+ $this->setOption('TrackingLastSend['.IRP_PLUGIN_SLUG.']', $value);
122
+ }
123
+ public function getPluginInstallDate() {
124
+ return $this->getOption('PluginInstallDate['.IRP_PLUGIN_SLUG.']', 0);
125
+ }
126
+ public function setPluginInstallDate($value) {
127
+ $this->setOption('PluginInstallDate['.IRP_PLUGIN_SLUG.']', $value);
128
+ }
129
+ public function getPluginUpdateDate() {
130
+ return $this->getOption('PluginUpdateDate['.IRP_PLUGIN_SLUG.']', 0);
131
+ }
132
+ public function setPluginUpdateDate($value) {
133
+ $this->setOption('PluginUpdateDate['.IRP_PLUGIN_SLUG.']', $value);
134
+ }
135
+
136
+ public function isPluginFirstInstall() {
137
+ return $this->getOption('PluginFirstInstall', FALSE);
138
+ }
139
+ public function setPluginFirstInstall($value) {
140
+ $this->setOption('PluginFirstInstall', $value);
141
+ }
142
+ public function isShowActivationNotice() {
143
+ return $this->getOption('ShowActivationNotice', FALSE);
144
+ }
145
+ public function setShowActivationNotice($value) {
146
+ $this->setOption('ShowActivationNotice', $value);
147
+ }
148
+
149
+ //LoggerEnable
150
+ public function isLoggerEnable() {
151
+ return ($this->getOption('LoggerEnable', FALSE) || (defined('IRP_LOGGER') && IRP_LOGGER));
152
+ }
153
+ public function setLoggerEnable($value) {
154
+ $this->setOption('LoggerEnable', $value);
155
+ }
156
+
157
+ //Cache
158
+ public function getCache($name, $id) {
159
+ return $this->getRequest('Cache_'.$name.'_'.$id);
160
+ }
161
+ public function setCache($name, $id, $value) {
162
+ $this->setRequest('Cache_'.$name.'_'.$id, $value);
163
+ }
164
+
165
+ public function getFeedbackEmail() {
166
+ return $this->getOption('FeedbackEmail', get_bloginfo('admin_email'));
167
+ }
168
+ public function setFeedbackEmail($value) {
169
+ $this->setOption('FeedbackEmail', $value);
170
+ }
171
+
172
+ private function hasGenericMessages($type) {
173
+ $result=$this->getRequest($type.'Messages', NULL);
174
+ return (is_array($result) && count($result)>0);
175
+ }
176
+
177
+ private function pushGenericMessage($type, $message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
178
+ global $irp;
179
+ $array=$this->getRequest($type.'Messages', array());
180
+ $array[]=$irp->Lang->L($message, $v1, $v2, $v3, $v4, $v5);
181
+ $this->setRequest($type.'Messages', $array);
182
+ }
183
+ private function writeGenericMessages($type, $clean=TRUE) {
184
+ $result=FALSE;
185
+ $array=$this->getRequest($type.'Messages', array());
186
+ if(is_array($array) && count($array)>0) {
187
+ $result=TRUE;
188
+ ?>
189
+ <div class="irp-box-<?php echo strtolower($type)?>"><?php echo wpautop(implode("\n", $array)); ?></div>
190
+ <?php }
191
+ if($clean) {
192
+ $this->removeRequest($type.'Messages');
193
+ }
194
+ return $result;
195
+ }
196
+ //WarningMessages
197
+ public function hasWarningMessages() {
198
+ return $this->hasGenericMessages('Warning');
199
+ }
200
+ public function pushWarningMessage($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
201
+ return $this->pushGenericMessage('Warning', $message, $v1, $v2, $v3, $v4, $v5);
202
+ }
203
+ public function writeWarningMessages($clean=TRUE) {
204
+ return $this->writeGenericMessages('Warning', $clean);
205
+ }
206
+ //SuccessMessages
207
+ public function hasSuccessMessages() {
208
+ return $this->hasGenericMessages('Success');
209
+ }
210
+ public function pushSuccessMessage($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
211
+ return $this->pushGenericMessage('Success', $message, $v1, $v2, $v3, $v4, $v5);
212
+ }
213
+ public function writeSuccessMessages($clean=TRUE) {
214
+ return $this->writeGenericMessages('Success', $clean);
215
+ }
216
+ //InfoMessages
217
+ public function hasInfoMessages() {
218
+ return $this->hasGenericMessages('Info');
219
+ }
220
+ public function pushInfoMessage($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
221
+ return $this->pushGenericMessage('Info', $message, $v1, $v2, $v3, $v4, $v5);
222
+ }
223
+ public function writeInfoMessages($clean=TRUE) {
224
+ return $this->writeGenericMessages('Info', $clean);
225
+ }
226
+ //ErrorMessages
227
+ public function hasErrorMessages() {
228
+ return $this->hasGenericMessages('Error');
229
+ }
230
+ public function pushErrorMessage($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
231
+ return $this->pushGenericMessage('Error', $message, $v1, $v2, $v3, $v4, $v5);
232
+ }
233
+ public function writeErrorMessages($clean=TRUE) {
234
+ return $this->writeGenericMessages('Error', $clean);
235
+ }
236
+
237
+ public function writeMessages($clean=TRUE) {
238
+ $result=FALSE;
239
+ if($this->writeInfoMessages($clean)) {
240
+ $result=TRUE;
241
+ }
242
+ if($this->writeSuccessMessages($clean)) {
243
+ $result=TRUE;
244
+ }
245
+ if($this->writeWarningMessages($clean)) {
246
+ $result=TRUE;
247
+ }
248
+ if($this->writeErrorMessages($clean)) {
249
+ $result=TRUE;
250
+ }
251
+
252
+ return $result;
253
+ }
254
+ public function pushMessage($success, $message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
255
+ if($success) {
256
+ $this->pushSuccessMessage($message.'Success', $v1, $v2, $v3, $v4, $v5);
257
+ } else {
258
+ $this->pushErrorMessage($message.'Error', $v1, $v2, $v3, $v4, $v5);
259
+ }
260
+ }
261
+ }
includes/classes/utils/Plugin.php ADDED
@@ -0,0 +1,263 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!defined('ABSPATH')) exit;
3
+
4
+ define('IRP_PLUGINS_NO_PLUGINS', 10000);
5
+ define('IRP_PLUGINS_WOOCOMMERCE', 10001);
6
+ define('IRP_PLUGINS_EDD', 10002);
7
+ define('IRP_PLUGINS_WP_ECOMMERCE', 10003);
8
+ define('IRP_PLUGINS_WP_SPSC', 10004);
9
+ define('IRP_PLUGINS_S2MEMBER', 10005);
10
+ define('IRP_PLUGINS_MEMBERS', 10006);
11
+ define('IRP_PLUGINS_CART66', 10007);
12
+ define('IRP_PLUGINS_ESHOP', 10008);
13
+ define('IRP_PLUGINS_JIGOSHOP', 10009);
14
+ define('IRP_PLUGINS_MARKETPRESS', 10010);
15
+ define('IRP_PLUGINS_SHOPP', 10011);
16
+ define('IRP_PLUGINS_SIMPLE_WP_ECOMMERCE', 10012);
17
+ define('IRP_PLUGINS_CF7', 10013);
18
+ define('IRP_PLUGINS_GRAVITY', 10014);
19
+ define('IRP_PLUGINS_TRACKING_CODE_MANAGER', 10015);
20
+ define('IRP_PLUGINS_TRACKING_CODE_MANAGER_PRO', 10016);
21
+ define('IRP_PLUGINS_INTELLY_RELATED_POSTS', 10017);
22
+ define('IRP_PLUGINS_INTELLY_RELATED_POSTS_PRO', 10018);
23
+
24
+ class IRP_Plugin {
25
+ function __construct() {
26
+ }
27
+
28
+ function getName($pluginId) {
29
+ $result='';
30
+ switch ($pluginId) {
31
+ case IRP_PLUGINS_WOOCOMMERCE:
32
+ $result='WooCommerce';
33
+ break;
34
+ case IRP_PLUGINS_EDD:
35
+ $result='Easy Digital Download';
36
+ break;
37
+ case IRP_PLUGINS_WP_ECOMMERCE:
38
+ $result='WP eCommerce';
39
+ break;
40
+ case IRP_PLUGINS_WP_SPSC:
41
+ $result='WordPress Simple Paypal Shopping Cart';
42
+ break;
43
+ case IRP_PLUGINS_S2MEMBER:
44
+ $result='s2member';
45
+ break;
46
+ case IRP_PLUGINS_MEMBERS:
47
+ $result='Members';
48
+ break;
49
+ case IRP_PLUGINS_CART66:
50
+ $result='Cart66 Lite :: WordPress Ecommerce';
51
+ break;
52
+ case IRP_PLUGINS_ESHOP:
53
+ $result='eShop';
54
+ break;
55
+ case IRP_PLUGINS_JIGOSHOP:
56
+ $result='Jigoshop';
57
+ break;
58
+ case IRP_PLUGINS_MARKETPRESS:
59
+ $result='MarketPress - WordPress eCommerce';
60
+ break;
61
+ case IRP_PLUGINS_SHOPP:
62
+ $result='Shopp';
63
+ break;
64
+ case IRP_PLUGINS_SIMPLE_WP_ECOMMERCE:
65
+ $result='iThemes Exchange: Simple WP Ecommerce';
66
+ break;
67
+ case IRP_PLUGINS_CF7:
68
+ $result='Contact Form 7';
69
+ break;
70
+ case IRP_PLUGINS_GRAVITY:
71
+ $result='Gravity Form';
72
+ break;
73
+ case IRP_PLUGINS_TRACKING_CODE_MANAGER:
74
+ $result='Tracking Code Manager';
75
+ break;
76
+ case IRP_PLUGINS_TRACKING_CODE_MANAGER_PRO:
77
+ $result='Tracking Code Manager PRO';
78
+ break;
79
+ case IRP_PLUGINS_INTELLY_RELATED_POSTS:
80
+ $result='Inline Related Posts';
81
+ break;
82
+ case IRP_PLUGINS_INTELLY_RELATED_POSTS_PRO:
83
+ $result='Inline Related Posts PRO';
84
+ break;
85
+ }
86
+ return $result;
87
+ }
88
+ function isActive($pluginId) {
89
+ global $tcm;
90
+
91
+ $php='';
92
+ $class='';
93
+ $constant='';
94
+ switch ($pluginId) {
95
+ case IRP_PLUGINS_WOOCOMMERCE:
96
+ $php='woocommerce/woocommerce.php';
97
+ $class='WooCommerce';
98
+ $constant='WOOCOMMERCE_VERSION';
99
+ break;
100
+ case IRP_PLUGINS_EDD:
101
+ $php='easy-digital-downloads/easy-digital-downloads.php';
102
+ $class='Easy_Digital_Downloads';
103
+ $constant='EDD_SL_VERSION';
104
+ break;
105
+ case IRP_PLUGINS_WP_ECOMMERCE:
106
+ $class='WP_eCommerce';
107
+ $constant='WPSC_VERSION';
108
+ break;
109
+ case IRP_PLUGINS_WP_SPSC:
110
+ $constant='WP_CART_VERSION';
111
+ break;
112
+ case IRP_PLUGINS_S2MEMBER:
113
+ $constant='WS_PLUGIN__S2MEMBER_VERSION';
114
+ break;
115
+ case IRP_PLUGINS_MEMBERS:
116
+ $constant='MEMBERS_VERSION';
117
+ break;
118
+ case IRP_PLUGINS_CART66:
119
+ $class='Cart66';
120
+ $constant='CART66_VERSION_NUMBER';
121
+ break;
122
+ case IRP_PLUGINS_ESHOP:
123
+ $constant='ESHOP_VERSION';
124
+ break;
125
+ case IRP_PLUGINS_JIGOSHOP:
126
+ $constant='JIGOSHOP_VERSION';
127
+ break;
128
+ case IRP_PLUGINS_MARKETPRESS:
129
+ $class='MarketPress';
130
+ $constant='MP_LITE';
131
+ break;
132
+ case IRP_PLUGINS_SHOPP:
133
+ $constant='ESHOP_VERSION';
134
+ break;
135
+ case IRP_PLUGINS_SIMPLE_WP_ECOMMERCE:
136
+ $class='IT_Exchange';
137
+ $constant='';
138
+ break;
139
+ case IRP_PLUGINS_CF7:
140
+ $constant='WPCF7_VERSION';
141
+ break;
142
+ case IRP_PLUGINS_GRAVITY:
143
+ $constant='';
144
+ break;
145
+ case IRP_PLUGINS_TRACKING_CODE_MANAGER:
146
+ $constant='TCM_PLUGIN_VERSION';
147
+ break;
148
+ case IRP_PLUGINS_TRACKING_CODE_MANAGER_PRO:
149
+ $constant='TCMP_PLUGIN_VERSION';
150
+ break;
151
+ case IRP_PLUGINS_INTELLY_RELATED_POSTS:
152
+ $constant='IRP_PLUGIN_VERSION';
153
+ break;
154
+ case IRP_PLUGINS_INTELLY_RELATED_POSTS_PRO:
155
+ $constant='IRPP_PLUGIN_VERSION';
156
+ break;
157
+ }
158
+ $result=$this->isPluginActive($class, $constant, $php);
159
+ return $result;
160
+ }
161
+
162
+ private function isPluginActive($class='', $constant='', $plugin='') {
163
+ $result=FALSE;
164
+ $result=($result || ($class!='' && class_exists($class)));
165
+ $result=($result || ($constant!='' && defined($constant)));
166
+ //require plugin.php
167
+ //$result=($result || ($plugin!='' && is_plugin_active($plugin)));
168
+ return $result;
169
+ }
170
+
171
+ function getVersion($pluginId) {
172
+ $constant='';
173
+ $version='';
174
+ switch ($pluginId) {
175
+ case IRP_PLUGINS_WOOCOMMERCE:
176
+ $constant='WOOCOMMERCE_VERSION';
177
+ break;
178
+ case IRP_PLUGINS_EDD:
179
+ $constant='EDD_SL_VERSION';
180
+ break;
181
+ case IRP_PLUGINS_WP_ECOMMERCE:
182
+ $constant='WPSC_VERSION';
183
+ break;
184
+ case IRP_PLUGINS_WP_SPSC:
185
+ $constant='WP_CART_VERSION';
186
+ break;
187
+ case IRP_PLUGINS_S2MEMBER:
188
+ $constant='WS_PLUGIN__S2MEMBER_VERSION';
189
+ break;
190
+ case IRP_PLUGINS_MEMBERS:
191
+ $constant='MEMBERS_VERSION';
192
+ break;
193
+ case IRP_PLUGINS_CART66:
194
+ $constant='CART66_VERSION_NUMBER';
195
+ break;
196
+ case IRP_PLUGINS_ESHOP:
197
+ $constant='ESHOP_VERSION';
198
+ break;
199
+ case IRP_PLUGINS_JIGOSHOP:
200
+ $constant='JIGOSHOP_VERSION';
201
+ break;
202
+ case IRP_PLUGINS_MARKETPRESS:
203
+ global $mp;
204
+ $version=$mp->version;
205
+ break;
206
+ case IRP_PLUGINS_SHOPP:
207
+ $constant='ESHOP_VERSION';
208
+ break;
209
+ case IRP_PLUGINS_SIMPLE_WP_ECOMMERCE:
210
+ $version=$GLOBALS['it_exchange']['version'];
211
+ break;
212
+ case IRP_PLUGINS_CF7:
213
+ $constant='WPCF7_VERSION';
214
+ break;
215
+ case IRP_PLUGINS_GRAVITY:
216
+ $constant='';
217
+ break;
218
+ case IRP_PLUGINS_TRACKING_CODE_MANAGER:
219
+ $constant='TCM_PLUGIN_VERSION';
220
+ break;
221
+ case IRP_PLUGINS_TRACKING_CODE_MANAGER_PRO:
222
+ $constant='TCMP_PLUGIN_VERSION';
223
+ break;
224
+ case IRP_PLUGINS_INTELLY_RELATED_POSTS:
225
+ $constant='IRP_PLUGIN_VERSION';
226
+ break;
227
+ case IRP_PLUGINS_INTELLY_RELATED_POSTS_PRO:
228
+ $constant='IRPP_PLUGIN_VERSION';
229
+ break;
230
+ }
231
+ if($version=='' && $constant!='') {
232
+ $version=(defined($constant) ? constant($constant) : '');
233
+ }
234
+ return $version;
235
+ }
236
+
237
+ function getActivePlugins($ids) {
238
+ return $this->getActivePlugins($ids, TRUE);
239
+ }
240
+ function getPlugins($ids, $onlyActive=TRUE) {
241
+ $array=array();
242
+ if(!is_array($ids)) {
243
+ $ids=array(intval($ids));
244
+ }
245
+
246
+ foreach($ids as $id) {
247
+ if(!$onlyActive || $this->isActive($id)) {
248
+ $name=$this->getName($id);
249
+ $version=$this->getVersion($id);
250
+
251
+ $v=array(
252
+ 'id'=>$id
253
+ , 'name'=>$name
254
+ , 'version'=>$version
255
+ , 'active'=>$this->isActive($id)
256
+ );
257
+ $array[$name]=$v;
258
+ }
259
+ }
260
+ ksort($array);
261
+ return $array;
262
+ }
263
+ }
includes/classes/utils/Tracking.php ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 IRP_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('irp_weekly_scheduled_events', array($this, 'sendTracking'));
19
+
20
+ //add_action('irp_tracking_on', array($this, 'enableTracking'));
21
+ //add_action('irp_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 $irp;
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=$irp->Utils->query(IRP_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
+ $data=array(
101
+ 'debug'=>(defined('WP_DEBUG') && WP_DEBUG)
102
+ , 'maxTime'=>$irp->Options->getMaxExecutionTime()
103
+ , 'active'=>$irp->Options->isActive()
104
+ , 'engineSearch'=>$irp->Options->getEngineSearch()
105
+ , 'rewriteAtEnd'=>$irp->Options->isRewriteAtEnd()
106
+ , 'rewriteThresold'=>$irp->Options->getRewriteThreshold()
107
+ , 'rewriteBoxesCount'=>$irp->Options->getRewriteBoxesCount()
108
+ , 'rewriteActive'=>$irp->Options->isRewriteActive()
109
+ , 'metaboxPostTypes'=>$irp->Options->getMetaboxPostTypes()
110
+ , 'rewritePostTypes'=>$irp->Options->getRewritePostTypes()
111
+ );
112
+ $data=$irp->Utils->parseArgs($irp->Options->getTemplateStyle(), $data);
113
+ $result['iwpm_plugin_name']=IRP_PLUGIN_SLUG;
114
+ $result['iwpm_plugin_version']=IRP_PLUGIN_VERSION;
115
+ $result['iwpm_plugin_data']=$data;
116
+ $result['iwpm_plugin_install_date']=$irp->Options->getPluginInstallDate();
117
+ $result['iwpm_plugin_update_date']=$irp->Options->getPluginUpdateDate();
118
+
119
+ $result['iwpm_tracking_enable']=$irp->Options->isTrackingEnable();
120
+ $result['iwpm_logger_enable']=$irp->Options->isLoggerEnable();
121
+ $result['iwpm_feedback_email']=$irp->Options->getFeedbackEmail();
122
+
123
+ return $result;
124
+ }
125
+
126
+ //send tracking data info to our server
127
+ public function sendTracking($override = FALSE) {
128
+ global $irp;
129
+
130
+ $result=-1;
131
+ if(!$override && !$irp->Options->isTrackingEnable())
132
+ return $result;
133
+
134
+ // Send a maximum of once per week
135
+ $last_send=$irp->Options->getTrackingLastSend();
136
+ if(!$override && $last_send>strtotime('-1 week'))
137
+ return $result;
138
+
139
+ //add_filter('https_local_ssl_verify', '__return_false');
140
+ //add_filter('https_ssl_verify', '__return_false');
141
+ //add_filter('block_local_requests', '__return_false');
142
+ $data=$irp->Utils->remotePost('usage', $this->getData());
143
+ if($data) {
144
+ $result=intval($data['id']);
145
+ $irp->Options->setTrackingLastSend(time());
146
+ }
147
+ return $result;
148
+ }
149
+
150
+ public function enableTracking() {
151
+ global $irp;
152
+
153
+ $irp->Options->setTrackingEnable(TRUE);
154
+ $irp->Options->setTrackingNotice(FALSE);
155
+ $this->sendTracking(TRUE);
156
+ }
157
+ public function disableTracking() {
158
+ global $irp;
159
+
160
+ $irp->Options->setTrackingEnable(FALSE);
161
+ $irp->Options->setTrackingNotice(FALSE);
162
+ $this->sendTracking(TRUE);
163
+ }
164
+
165
+ public function admin_notice() {
166
+ global $irp;
167
+
168
+ if(!$irp->Options->isTrackingNotice() || $irp->Options->isTrackingEnable() || !current_user_can('manage_options'))
169
+ return;
170
+
171
+ if(FALSE && (
172
+ stristr(network_site_url('/'), 'dev' ) !== false ||
173
+ stristr(network_site_url('/'), 'localhost') !== false ||
174
+ stristr(network_site_url('/'), ':8888' ) !== false // This is common with MAMP on OS X
175
+ )) {
176
+ $irp->Options->setTrackingNotice(TRUE);
177
+ } else {
178
+ $yes_url=add_query_arg('irp_action', 'manager_trackingOn');
179
+ $no_url=add_query_arg('irp_action', 'manager_trackingOff');
180
+
181
+ ?>
182
+ <div class="updated">
183
+ <p>
184
+ <?php $irp->Lang->P('Allow IntellyWP to track plugin usage?');?>
185
+ &nbsp;<a href="<?php echo esc_url($yes_url)?>" class="button-primary"><?php $irp->Lang->P('Oh yes :)')?></a>
186
+ &nbsp;<a href="<?php echo esc_url($no_url)?>" class="button-secondary"><?php $irp->Lang->P('Refuse!')?></a>
187
+ </p>
188
+ </div>
189
+ <?php }
190
+ }
191
+ }
includes/classes/utils/Utils.php ADDED
@@ -0,0 +1,599 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) exit;
3
+
4
+ class IRP_Utils {
5
+
6
+ function format($message, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
7
+ if($v1 || $v2 || $v3 || $v4 || $v5) {
8
+ $message=sprintf($message, $v1, $v2, $v3, $v4, $v5);
9
+ }
10
+ return $message;
11
+ }
12
+ function startsWith($haystack, $needle) {
13
+ $result=FALSE;
14
+ if (is_array($needle)) {
15
+ foreach($needle as $w) {
16
+ if ($this->startsWith($haystack, $w)) {
17
+ $result=TRUE;
18
+ break;
19
+ }
20
+ }
21
+ } elseif($needle!='') {
22
+ if(is_array($haystack)) {
23
+ foreach($haystack as $h) {
24
+ if($this->startsWith($h, $needle)) {
25
+ $result=TRUE;
26
+ break;
27
+ }
28
+ }
29
+ } elseif($haystack!='') {
30
+ $length = strlen($needle);
31
+ $result = (substr($haystack, 0, $length) === $needle);
32
+ }
33
+ }
34
+ return $result;
35
+ }
36
+ function endsWith($haystack, $needle) {
37
+ $result=FALSE;
38
+ if (is_array($needle)) {
39
+ foreach($needle as $w) {
40
+ if ($this->endsWith($haystack, $w)) {
41
+ $result=TRUE;
42
+ break;
43
+ }
44
+ }
45
+ } elseif($needle!='') {
46
+ if(is_array($haystack)) {
47
+ foreach($haystack as $h) {
48
+ if($this->endsWith($h, $needle)) {
49
+ $result=TRUE;
50
+ break;
51
+ }
52
+ }
53
+ } elseif($haystack!='') {
54
+ $length = strlen($needle);
55
+ $start = $length * -1; //negative
56
+ $result=(substr($haystack, $start) === $needle);
57
+ }
58
+ }
59
+ return $result;
60
+ }
61
+ function substr($text, $start=0, $end=-1) {
62
+ if($end<0) {
63
+ $end=strlen($text);
64
+ }
65
+ $length=$end-$start;
66
+ return substr($text, $start, $length);
67
+ }
68
+
69
+ //WOW! $end is passed as reference due to we can change it if we found \n character after
70
+ //substring to avoid having these characters after or before
71
+ function substrln($text, $start=0, &$end=-1) {
72
+ if($end<0) {
73
+ $end=strlen($text);
74
+ }
75
+
76
+ do {
77
+ $loop=FALSE;
78
+ $c=substr($text, $end, 1);
79
+ if($c=="\n" || $c=="\r" || $c==".") {
80
+ $end += 1;
81
+ $loop=TRUE;
82
+ }
83
+ } while($loop);
84
+
85
+ $length=$end-$start;
86
+ return substr($text, $start, $length);
87
+ }
88
+
89
+ function toCommaArray($array, $isNumeric=TRUE, $isTrim=TRUE) {
90
+ if(is_string($array)) {
91
+ if(trim($array)=='') {
92
+ $array=array();
93
+ } else {
94
+ $array=explode(',', $array);
95
+ }
96
+ } elseif(is_numeric($array)) {
97
+ $array=array($array);
98
+ }
99
+ if(!is_array($array)) {
100
+ $array=array();
101
+ }
102
+ for($i=0; $i<count($array); $i++) {
103
+ if($isTrim) {
104
+ $array[$i]=trim($array[$i]);
105
+ }
106
+ if($isNumeric) {
107
+ $array[$i]=floatval($array[$i]);
108
+ }
109
+ }
110
+ return $array;
111
+ }
112
+ //verifica se il parametro needle è un elemento dell'array haystack
113
+ //se il parametro needle è a sua volta un array verifica che almeno un elemento
114
+ //sia contenuto all'interno dell'array haystack
115
+ function inArray($needle, $haystack) {
116
+ if (is_string($haystack)) {
117
+ //from string to numeric array
118
+ $temp = explode(',', $haystack);
119
+ $haystack = array();
120
+ foreach ($temp as $v) {
121
+ $v = trim($v);
122
+ $v = intval($v);
123
+ if ($v > 0) {
124
+ $haystack[] = $v;
125
+ }
126
+ }
127
+ }
128
+
129
+ $result = FALSE;
130
+ foreach ($haystack as $v) {
131
+ $v = intval($v);
132
+ //if one element of the array have -1 value means i select "all" option
133
+ if ($v < 0) {
134
+ $result = TRUE;
135
+ break;
136
+ }
137
+ }
138
+
139
+ if ($result) {
140
+ return TRUE;
141
+ }
142
+
143
+ $result = FALSE;
144
+ if (is_array($needle)) {
145
+ foreach ($needle as $v) {
146
+ $v = trim($v);
147
+ $v = intval($v);
148
+ if (in_array($v, $haystack)) {
149
+ $result = TRUE;
150
+ break;
151
+ }
152
+ }
153
+ } else {
154
+ //built-in comparison
155
+ $result = in_array($needle, $haystack);
156
+ }
157
+ return $result;
158
+ }
159
+
160
+ function is($name, $compare, $default='', $ignoreCase=TRUE) {
161
+ $what=$this->qs($name, $default);
162
+ $result=FALSE;
163
+ if(is_string($compare)) {
164
+ $compare=explode(',', $compare);
165
+ }
166
+ if($ignoreCase){
167
+ $what=strtolower($what);
168
+ }
169
+
170
+ foreach($compare as $v) {
171
+ if($ignoreCase){
172
+ $v=strtolower($v);
173
+ }
174
+ if($what==$v) {
175
+ $result=TRUE;
176
+ break;
177
+ }
178
+ }
179
+ return $result;
180
+ }
181
+
182
+ public function twitter($name) {
183
+ ?>
184
+ <a href="https://twitter.com/<?php echo $name?>" class="twitter-follow-button" data-show-count="false" data-dnt="true">Follow @<?php echo $name?></a>
185
+ <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
186
+ <?php
187
+ }
188
+
189
+ function aqs($prefix, $defaults=array()) {
190
+ global $irp;
191
+
192
+ $removePrefix=TRUE;
193
+ $args=array();
194
+ $array=$this->merge(TRUE, $_POST, $_GET);
195
+ foreach($array as $k=>$v) {
196
+ if($this->startsWith($k, $prefix)) {
197
+ if($removePrefix) {
198
+ $k=substr($k, strlen($prefix));
199
+ }
200
+ $args[$k]=$v;
201
+ }
202
+ }
203
+ $args=$irp->Utils->parseArgs($args, $defaults);
204
+ return $args;
205
+ }
206
+ function iqs($name, $default = 0) {
207
+ return intval($this->qs($name, $default));
208
+ }
209
+ //per ottenere un campo dal $_GET oppure dal $_POST
210
+ function qs($name, $default = '') {
211
+ $result = $default;
212
+ if (isset($_GET[$name])) {
213
+ $result = $_GET[$name];
214
+ } elseif (isset($_POST[$name])) {
215
+ $result = $_POST[$name];
216
+ }
217
+
218
+ if (is_string($result)) {
219
+ $result = urldecode($result);
220
+ $result = trim($result);
221
+ }
222
+
223
+ return $result;
224
+ }
225
+
226
+ function query($query, $args = NULL) {
227
+ global $irp;
228
+
229
+ $defaults = array('post_type' => '', 'all' => FALSE, 'select' => FALSE);
230
+ $args = wp_parse_args($args, $defaults);
231
+
232
+ $result = $irp->Options->getCache('Query', $query . '_' . $args['post_type']);
233
+ if (!is_array($result) || count($result) == 0) {
234
+ $q = NULL;
235
+ $id = 'ID';
236
+ $name = 'post_title';
237
+ $function='';
238
+ switch ($query) {
239
+ case IRP_QUERY_POSTS_OF_TYPE:
240
+ $options = array('posts_per_page' => -1, 'post_type' => $args['post_type']);
241
+ $q = get_posts($options);
242
+ $function='get_permalink';
243
+ break;
244
+ case IRP_QUERY_CATEGORIES:
245
+ $options = array('posts_per_page' => -1);
246
+ $q = get_categories($options);
247
+ $id = 'cat_ID';
248
+ $name = 'cat_name';
249
+ $function='get_category_link';
250
+ break;
251
+ case IRP_QUERY_TAGS:
252
+ $q = get_tags();
253
+ $id = 'term_id';
254
+ $name = 'name';
255
+ $function='get_tag_link';
256
+ break;
257
+ }
258
+
259
+ $result = array();
260
+ if ($q) {
261
+ foreach ($q as $v) {
262
+ $result[] = array('id' => $v->$id, 'name' => $v->$name);
263
+ }
264
+ } elseif ($query == IRP_QUERY_POST_TYPES) {
265
+ //$options = array('public' => TRUE, '_builtin' => FALSE);
266
+ //$q = get_post_types($options, 'names');
267
+ $q=array();
268
+ $q = array_merge($q, array('post', 'page'));
269
+ sort($q);
270
+ foreach ($q as $v) {
271
+ $result[] = array('id' => $v, 'name' => $v);
272
+ }
273
+ }
274
+
275
+ if($function!='' && function_exists($function)) {
276
+ for($i=0; $i<count($result); $i++) {
277
+ $v=$result[$i];
278
+ $v['url']=call_user_func_array($function, array($v['id']));
279
+ $result[$i]=$v;
280
+ }
281
+ }
282
+ $irp->Options->setCache('Query', $query . '_' . $args['post_type'], $result);
283
+ }
284
+
285
+ if ($args['all']) {
286
+ $first = array();
287
+ $first[] = array('id' => -1, 'name' => '[' . $irp->Lang->L('All') . ']', 'url'=>'');
288
+ $result = array_merge($first, $result);
289
+ }
290
+ if ($args['select']) {
291
+ $first = array();
292
+ $first[] = array('id' => 0, 'name' => '[' . $irp->Lang->L('Select') . ']', 'url'=>'');
293
+ $result = array_merge($first, $result);
294
+ }
295
+
296
+ return $result;
297
+ }
298
+
299
+ function remoteGet($uri, $options) {
300
+ global $irpp;
301
+ $result=FALSE;
302
+ $uri=add_query_arg($options, $uri);
303
+ //$uri=str_replace('https://', 'http://', $uri);
304
+
305
+ $args=array('timeout'=>15, 'sslverify'=>false);
306
+ $irpp->Log->debug('REMOTEGET: URI=%s', $uri);
307
+ $response=FALSE;//wp_remote_get($uri, $args);
308
+ if (FALSE && !is_wp_error($response)) {
309
+ // decode the license data
310
+ $body=wp_remote_retrieve_body($response);
311
+ if($body!==FALSE && $body!='') {
312
+ $irpp->Log->debug('REMOTEGET: RETRIEVEBODY=%s', $body);
313
+ $result=json_decode($body);
314
+ if(!$result) {
315
+ $irpp->Log->error('REMOTEGET: UNDECODABLE BODY');
316
+ if(strpos($body, 'debug')!==FALSE || strpos($body, 'fatal')!==FALSE || strpos($body, 'warning')!==FALSE || strpos($body, 'error')!==FALSE) {
317
+ $irpp->Options->pushErrorMessage('XdebugException');
318
+ }
319
+ }
320
+ } else {
321
+ $irpp->Log->debug('REMOTEGET: RETRIEVEBODY ERROR');
322
+ $result=FALSE;
323
+ }
324
+ } else {
325
+ $irpp->Log->debug('REMOTEGET: RESULT=ERROR');
326
+ }
327
+ if($result===FALSE) {
328
+ $irpp->Log->debug('file_get_contents: URI=%s', $uri);
329
+
330
+ $ch=curl_init();
331
+ $timeout=900;
332
+ curl_setopt($ch, CURLOPT_URL, $uri);
333
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
334
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
335
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
336
+ curl_setopt($ch, CURLOPT_FAILONERROR, TRUE);
337
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
338
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
339
+ curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
340
+ $body=curl_exec($ch);
341
+ curl_close($ch);
342
+
343
+ $irpp->Log->debug('file_get_contents: RETRIEVEBODY=%s', $body);
344
+ if($body!==FALSE && $body!='') {
345
+ $irpp->Log->debug('REMOTEGET: RETRIEVEBODY=%s', $body);
346
+ $result=json_decode($body);
347
+ if(!$result) {
348
+ $irpp->Log->error('REMOTEGET: UNDECODABLE BODY');
349
+ if(strpos($body, 'xdebug')!==FALSE) {
350
+ $irpp->Options->pushErrorMessage('XdebugException');
351
+ }
352
+ }
353
+ } else {
354
+ $irpp->Log->debug('REMOTEGET: RETRIEVEBODY ERROR');
355
+ $result=FALSE;
356
+ }
357
+ }
358
+ if(!$result) {
359
+ $result=FALSE;
360
+ }
361
+ return $result;
362
+ }
363
+ function remotePost($action, $data = '') {
364
+ global $irp;
365
+
366
+ $data['secret'] = 'WYSIWYG';
367
+ $response = wp_remote_post(IRP_INTELLYWP_ENDPOINT.'?iwpm_action=' . $action, array(
368
+ 'method' => 'POST'
369
+ , 'timeout' => 20
370
+ , 'redirection' => 5
371
+ , 'httpversion' => '1.1'
372
+ , 'blocking' => TRUE
373
+ , 'body' => $data
374
+ , 'user-agent' => 'IRPP/' . IRP_PLUGIN_VERSION . '; ' . get_bloginfo('url')
375
+ ));
376
+ $data = json_decode(wp_remote_retrieve_body($response), TRUE);
377
+ if (is_wp_error($response) || wp_remote_retrieve_response_code($response) != 200
378
+ || !isset($data['success']) || !$data['success']
379
+ ) {
380
+ $irp->Log->error('ERRORS SENDING REMOTE-POST ACTION=%s DUE TO REASON=%s', $action, $response);
381
+ $data = FALSE;
382
+ } else {
383
+ $irp->Log->debug('SUCCESSFULLY SENT REMOTE-POST ACTION=%s RESPONSE=%s', $action, $data);
384
+ }
385
+ return $data;
386
+ }
387
+
388
+ function shortcodeAtts($defaults, $atts) {
389
+ if(!is_array($atts)) {
390
+ $atts=array();
391
+ }
392
+
393
+ $array=array();
394
+ foreach($defaults as $k=>$v) {
395
+ if (array_key_exists($k, $atts) ) {
396
+ $array[$k] = $atts[$k];
397
+ } elseif (array_key_exists(strtolower($k), $atts) ) {
398
+ $array[$k] = $atts[strtolower($k)];
399
+ } else {
400
+ $array[$k] = $v;
401
+ }
402
+ }
403
+ return $array;
404
+ }
405
+
406
+ //wp_parse_args with null correction
407
+ function parseArgs($args, $defaults) {
408
+ if (is_null($args) || !is_array($args)) {
409
+ $args = array();
410
+ }
411
+ foreach ($args as $k => $v) {
412
+ if (is_null($args[$k])) {
413
+ //so can take the default value
414
+ unset($args[$k]);
415
+ } elseif (is_string($args[$k]) && $args[$k] == '' && isset($defaults[$k]) && is_array($defaults[$k])) {
416
+ //a very strange case, i have a blank string for rappresenting an empty array
417
+ unset($args[$k]);
418
+ }
419
+ }
420
+ $result = wp_parse_args($args, $defaults);
421
+ return $result;
422
+ }
423
+
424
+ function redirect($location) {
425
+ if(!headers_sent()) {
426
+ wp_redirect($location);
427
+ }
428
+ ?>
429
+ <script> window.location.replace('<?php echo $location?>'); </script>
430
+ <?php }
431
+
432
+ //return the element inside array with the specified key
433
+ function getArrayValue($key, $array, $value='') {
434
+ $result=FALSE;
435
+ if (isset($array[$key])) {
436
+ $result=$array[$key];
437
+ $result['name']=$key;
438
+ }
439
+ if($result!==FALSE && $value!='') {
440
+ if(isset($result[$value])) {
441
+ $result=$result[$value];
442
+ }
443
+ }
444
+ return $result;
445
+ }
446
+
447
+ var $_sortField;
448
+ var $_ignoreCase;
449
+ function aksort(&$array, $sortField='name', $ignoreCase=TRUE) {
450
+ $this->_sortField=$sortField;
451
+ $this->_ignoreCase=$ignoreCase;
452
+ usort($array, array($this, "aksortCompare"));
453
+ }
454
+ //not thread-safe!
455
+ private function aksortCompare($a, $b) {
456
+ if ($a===$b || $a==$b) {
457
+ return 0;
458
+ }
459
+
460
+ $result=0;
461
+ $a=$a[$this->_sortField];
462
+ $b=$b[$this->_sortField];
463
+ if(is_numeric($a) && is_numeric($b)) {
464
+ $result=($a < $b) ? -1 : 1;
465
+ } else {
466
+ $a.='';
467
+ $b.='';
468
+ if($this->_ignoreCase) {
469
+ $result=strcasecmp($a, $b);
470
+ } else {
471
+ $result=strcmp($a.'', $b);
472
+ }
473
+ }
474
+ return $result;
475
+ }
476
+
477
+ function printScriptCss() {
478
+ global $irp;
479
+ $uri=get_bloginfo('wpurl');
480
+ $irp->Tabs->enqueueScripts();
481
+ //wp_enqueue_style('buttons', $uri.'/wp-includes/css/buttons.min.css');
482
+ //wp_enqueue_style('editor', $uri.'/wp-includes/css/editor.min.css');
483
+ //wp_enqueue_style('jquery-ui-dialog', $uri.'/wp-includes/css/jquery-ui-dialog.min.css');
484
+ $styles='dashicons,admin-bar,buttons,media-views,wp-admin,wp-auth-check,wp-color-picker';
485
+ $styles=explode(',', $styles);
486
+ foreach($styles as $v) {
487
+ wp_enqueue_style($v);
488
+ }
489
+
490
+ remove_all_actions('wp_print_scripts');
491
+ print_head_scripts();
492
+ print_admin_styles();
493
+ }
494
+
495
+ public function sort($isAssociative, $a1, $a2=NULL, $a3=NULL, $a4=NULL, $a5=NULL) {
496
+ $array=$this->merge($isAssociative, $a1, $a2, $a3, $a4, $a5);
497
+ ksort($array);
498
+ return $array;
499
+ }
500
+ public function merge($isAssociative, $a1, $a2=NULL, $a3=NULL, $a4=NULL, $a5=NULL) {
501
+ $result=array();
502
+ if($isAssociative) {
503
+ $array=array($a1, $a2, $a3, $a4, $a5);
504
+ foreach($array as $a) {
505
+ if(!is_array($a)) {
506
+ continue;
507
+ }
508
+
509
+ foreach($a as $k=>$v) {
510
+ if(!isset($result[$k])) {
511
+ $result[$k]=$v;
512
+ }
513
+ }
514
+ }
515
+ } else {
516
+ $result=array_merge($a1, $a2, $a3, $a4, $a5);
517
+ }
518
+ return $result;
519
+ }
520
+ function get($array, $name, $default='') {
521
+ $result=$default;
522
+ if(isset($array[$name])) {
523
+ $result=$array[$name];
524
+ }
525
+ return $result;
526
+ }
527
+ function geti($array, $name, $default='') {
528
+ $result=$default;
529
+ $name=strtolower($name);
530
+ foreach($array as $k=>$v) {
531
+ if(strtolower($k)==$name) {
532
+ $result=$v;
533
+ break;
534
+ }
535
+ }
536
+ if(isset($array[$name])) {
537
+ $result=$array[$name];
538
+ }
539
+ return $result;
540
+ }
541
+ function iget($array, $name, $default='') {
542
+ return intval($this->get($array, $name, $default));
543
+ }
544
+ function isTrue($value) {
545
+ $result=FALSE;
546
+ if(is_bool($value)) {
547
+ $result=(bool)$value;
548
+ } elseif(is_numeric($value)) {
549
+ $result=floatval($value)>0;
550
+ } elseif(is_string($value)) {
551
+ $result=strtolower($value);
552
+ if($result=='ok' || $result=='yes' || $result=='true') {
553
+ $result=TRUE;
554
+ }
555
+ }
556
+ return $result;
557
+ }
558
+ function trimCode($code) {
559
+ $code=str_replace("\t", "", $code);
560
+ $code=str_replace("\r", "", $code);
561
+ $code=str_replace("\n", "", $code);
562
+ while(strpos($code, " ")!==FALSE) {
563
+ $code=str_replace(" ", " ", $code);
564
+ }
565
+ $code=str_replace("> <", "><", $code);
566
+ $code=trim($code);
567
+ return $code;
568
+ }
569
+ function getUUID($options) {
570
+ $buffer='';
571
+ if(is_string($options)) {
572
+ $buffer=$options;
573
+ } elseif(is_array($options)) {
574
+ foreach($options as $k=>$v) {
575
+ $buffer.=', '.$k.'='.$v;
576
+ }
577
+ }
578
+ if($buffer!='') {
579
+ $buffer='u'.md5($buffer);
580
+ }
581
+ return $buffer;
582
+ }
583
+
584
+ function isAdminUser() {
585
+ //https://wordpress.org/support/topic/how-to-check-admin-right-without-include-pluggablephp
586
+ return TRUE;
587
+ /*
588
+ if (!function_exists('wp_get_current_user')) {
589
+ require_once(ABSPATH . 'wp-includes/pluggable.php');
590
+ }
591
+ return (is_multisite() || current_user_can('manage_options'));
592
+ */
593
+ }
594
+ function isPluginPage() {
595
+ $page=$this->qs('page');
596
+ $result=(stripos($page, IRP_PLUGIN_SLUG)!==FALSE);
597
+ return $result;
598
+ }
599
+ }
includes/core.php ADDED
@@ -0,0 +1,335 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ add_filter('wp_head', 'irp_head');
3
+ function irp_head() {
4
+ global $post, $irp;
5
+
6
+ if($irp->Plugin->isActive(IRP_PLUGINS_INTELLY_RELATED_POSTS_PRO)) {
7
+ return;
8
+ }
9
+
10
+ $irp->Log->startTime('irp_head');
11
+ if($irp->Options->getPostShown()===FALSE || is_null($irp->Options->getPostShown())) {
12
+ $irp->Options->initRelatedPostsIds(NULL);
13
+ $irp->Options->setPostShown(NULL);
14
+ if($post && isset($post->ID) && is_single($post->ID)) {
15
+ $irp->Options->setPostShown($post);
16
+ $args=array('postId'=>$post->ID, 'shuffle'=>TRUE, 'count'=>-1);
17
+ $ids=$irp->Manager->getRelatedPostsIds($args);
18
+ $irp->Options->initRelatedPostsIds($ids);
19
+ //$irp->Log->info('POST ID=%s IS SHOWN, RELATED POSTS=%s', $post->ID, $ids);
20
+ }
21
+ }
22
+ $irp->Log->pauseTime();
23
+ }
24
+ add_filter('wp_footer', 'irp_footer');
25
+ //add_filter('admin_footer', 'irp_footer');
26
+ function irp_footer() {
27
+ global $irp;
28
+ if($irp->Plugin->isActive(IRP_PLUGINS_INTELLY_RELATED_POSTS_PRO)) {
29
+ return;
30
+ }
31
+
32
+ $irp->Log->startTime('irp_footer');
33
+ $array=$irp->Options->getCssStyles();
34
+ if(count($array)>0) {
35
+ echo "<style>\n";
36
+ foreach($array as $v) {
37
+ echo $v;
38
+ echo "\n";
39
+ }
40
+ echo "</style>\n";
41
+ }
42
+ $irp->Log->pauseTime();
43
+ $irp->Log->stopTime();
44
+ }
45
+
46
+ if(!shortcode_exists('irp')) {
47
+ add_shortcode('irp', 'irp_shortcode');
48
+ }
49
+ function irp_shortcode($atts, $content='') {
50
+ global $irp, $post;
51
+ if($irp->Plugin->isActive(IRP_PLUGINS_INTELLY_RELATED_POSTS_PRO)) {
52
+ return $content;
53
+ }
54
+ if(!$irp->Options->isActive()) {
55
+ return '';
56
+ }
57
+
58
+ $default=array(
59
+ 'posts'=>''
60
+ , 'cats'=>''
61
+ , 'tags'=>''
62
+ , 'count'=>1
63
+ , 'theme'=>''
64
+ , 'demo'=>FALSE
65
+ , 'ctaText'=>'default'
66
+ , 'ctaTextColor'=>'default'
67
+ , 'postTitleColor'=>'default'
68
+ , 'boxColor'=>'default'
69
+ , 'borderColor'=>'default'
70
+ , 'hasPoweredBy'=>'default'
71
+ , 'hasShadow'=>'default'
72
+ , 'defaultsColors'=>FALSE
73
+ , 'includeCss'=>TRUE
74
+ );
75
+ $options=$irp->Utils->shortcodeAtts($default, $atts);
76
+ if(isset($options['postId'])) {
77
+ unset($options['postId']);
78
+ }
79
+ $options['demo']=$irp->Utils->isTrue($options['demo']);
80
+ $options['count']=intval($options['count']);
81
+ if($options['count']<=0) {
82
+ return '';
83
+ }
84
+
85
+ if($options['posts']=='' && $options['cats']=='' && $options['tags']=='') {
86
+ //dynamic
87
+ $ids=$irp->Options->getToShowPostsIds($options['count'], TRUE);
88
+ } else {
89
+ if($options['posts']=='current' && $post && isset($post->ID)) {
90
+ $options['posts']=$post->ID;
91
+ }
92
+ //static
93
+ $ids=$irp->Manager->getRelatedPostsIds($options);
94
+ }
95
+
96
+ $keys=array('ctaText', 'ctaTextColor', 'postTitleColor', 'boxColor', 'borderColor', 'hasPoweredBy', 'hasShadow');
97
+ foreach($keys as $k) {
98
+ if($options[$k]=='default') {
99
+ unset($options[$k]);
100
+ }
101
+ }
102
+ $result=irp_ui_get_box($ids, $options);
103
+ if($result!='') {
104
+ $irp->Options->setShortcodeUsed(TRUE);
105
+ }
106
+ return $result;
107
+ }
108
+
109
+ function irp_ui_get_box($ids, $options=NULL) {
110
+ global $irp;
111
+ if($irp->Plugin->isActive(IRP_PLUGINS_INTELLY_RELATED_POSTS_PRO)) {
112
+ return "";
113
+ }
114
+ if(!is_array($ids) || count($ids)==0) {
115
+ return "";
116
+ }
117
+ if(!is_array($options)) {
118
+ $options=array();
119
+ }
120
+
121
+ $irp->Log->startTime('irp_ui_get_box');
122
+ $defaults=array(
123
+ 'includeCss'=>TRUE
124
+ , 'comment'=>''
125
+ , 'shortcode'=>FALSE
126
+ , 'preview'=>FALSE
127
+ , 'theme'=>''
128
+ , 'demo'=>FALSE
129
+ , 'array'=>FALSE
130
+ , 'defaultsColors'=>FALSE
131
+ );
132
+ $options=$irp->Utils->parseArgs($options, $defaults);
133
+ $body='';
134
+ if($options['shortcode']) {
135
+ $body='[irpx posts="'.implode(',', $ids).'" comment="'.$options['comment'].'"]';
136
+ } else {
137
+ $defaults=$irp->Options->getTemplateStyle();
138
+ $options=$irp->Utils->parseArgs($options, $defaults);
139
+ if($options['theme']!='') {
140
+ $options['template']=$options['theme'];
141
+ }
142
+ unset($options['theme']);
143
+
144
+ $posts=array();
145
+ foreach($ids as $postId) {
146
+ $v=get_post($postId);
147
+ if($v) {
148
+ $posts[]=$v;
149
+ }
150
+ }
151
+ if(count($posts)>0) {
152
+ foreach($posts as $v) {
153
+ $options['postHref']=get_permalink($v->ID);
154
+ $options['postTitle']=$v->post_title;
155
+
156
+ $options['postImageUrl']='';
157
+ //$options['postImageWidth']=0;
158
+ //$options['postImageHeight']=0;
159
+ $attachmentId=get_post_thumbnail_id($v->ID);
160
+ if($attachmentId!==FALSE && $attachmentId!=='' && intval($attachmentId)>0) {
161
+ $array=wp_get_attachment_image_src($attachmentId, 'medium');
162
+ if($array!==FALSE) {
163
+ $options['postImageUrl']=$array[0];
164
+ //$options['postImageWidth']=$array[1];
165
+ //$options['postImageHeight']=$array[2];
166
+ }
167
+ }
168
+ break;
169
+ }
170
+
171
+ if($irp->Utils->isTrue($options['defaultsColors'])) {
172
+ $defaults = $irp->HtmlTemplate->getDefaults();
173
+ $defaults = $defaults[$options['template']];
174
+ foreach ($defaults as $k => $v) {
175
+ $options[$k] = $v;
176
+ }
177
+ }
178
+ if($irp->Utils->isTrue($options['demo'])) {
179
+ $options['postHref']='javascript:void(0);';
180
+ $options['linkRel']='nofollow';
181
+ $options['linkTarget']='';
182
+ //$options['hasShadow']=TRUE;
183
+ //$options['hasPoweredBy']=1;
184
+ $ctaText=$irp->Utils->qs('ctaText');
185
+ if($ctaText!='') {
186
+ $options['ctaText']=$ctaText;
187
+ }
188
+ $postTitle=$irp->Utils->qs('postTitle');
189
+ $postTitle=str_replace("\\\"", "\"", $postTitle);
190
+ if($postTitle!='') {
191
+ $options['postTitle']=$postTitle;
192
+ }
193
+ $uri=$irp->Utils->qs('postImageUrl');
194
+ //$w=$irp->Utils->iqs('postImageWidth');
195
+ //$h=$irp->Utils->iqs('postImageHeight');
196
+ if($uri!='') {
197
+ $options['postImageUrl']=$uri;
198
+ //$options['postImageWidth']=$w;
199
+ //$options['postImageHeight']=$h;
200
+ }
201
+ } elseif($irp->Utils->isTrue($options['preview'])) {
202
+ $options['postHref']='javascript:IRP_changeRelatedBox();';
203
+ $options['linkRel']='nofollow';
204
+ $options['linkTarget']='';
205
+ }
206
+
207
+ $body=$options;
208
+ if($options['array']==FALSE) {
209
+ $body=$irp->HtmlTemplate->html($options['template'], $options, $options);
210
+ }
211
+ }
212
+ }
213
+ $irp->Log->pauseTime();
214
+ return $body;
215
+ }
216
+
217
+ /*add_filter('the_content', 'irp_fix_the_content');
218
+ function irp_fix_the_content($content) {
219
+ //this is to prevent wrong rewrite of WP of our content
220
+ $content=str_replace("<p></a></p>", "</a>", $content);
221
+ $content=str_replace("<p></a>", "</a>", $content);
222
+ return $content;
223
+ }*/
224
+ //add_filter('wp_head', 'irp_the_content');
225
+ add_filter('the_content', 'irp_the_content', 99999);
226
+ function irp_the_content($content) {
227
+ global $irp, $post;
228
+
229
+ if($irp->Plugin->isActive(IRP_PLUGINS_INTELLY_RELATED_POSTS_PRO)) {
230
+ return $content;
231
+ }
232
+
233
+ $irp->Log->startTime('irp_the_content');
234
+ if(!$post || trim($content)=='') {
235
+ return $content;
236
+ }
237
+
238
+ if($irp->Options->getPostShown()===FALSE || is_null($irp->Options->getPostShown())) {
239
+ $irp->Options->initRelatedPostsIds(NULL);
240
+ $irp->Options->setPostShown(NULL);
241
+ if($post && isset($post->ID) && is_single($post->ID)) {
242
+ $irp->Options->setPostShown($post);
243
+ $args=array('postId'=>$post->ID, 'shuffle'=>TRUE, 'count'=>-1);
244
+ $ids=$irp->Manager->getRelatedPostsIds($args);
245
+ $irp->Options->initRelatedPostsIds($ids);
246
+ //$irp->Log->info('POST ID=%s IS SHOWN, RELATED POSTS=%s', $post->ID, $ids);
247
+ }
248
+ } else {
249
+ $irp->Options->refreshRelatedPostsIds();
250
+ }
251
+
252
+ if($irp->Options->isPostShownExcluded()) {
253
+ $irp->Log->error('TheContent: POST UNDEFINED OR POST EXCLUDED');
254
+ return $content;
255
+ }
256
+
257
+ if(!$irp->Options->isActive() || !$irp->Options->isRewriteActive()) {
258
+ $irp->Log->error('TheContent: NOT ACTIVE NOT REWRITE ACTIVE');
259
+ return $content;
260
+ }
261
+ if($irp->Options->isShortcodeUsed()) {
262
+ $irp->Log->error('TheContent: NOT ACTIVE DUE TO SHORTCODE USED');
263
+ return $content;
264
+ }
265
+ if(!$irp->Options->hasRelatedPostsIds()) {
266
+ $irp->Log->error('TheContent: NOT ACTIVE DUE TO WITHOUT RELATED POSTS');
267
+ return $content;
268
+ }
269
+
270
+ $body=$content;
271
+ /*if(strpos($body, '[irp')!==FALSE) {
272
+ $irp->Log->error('TheContent: SHORTCODE DETECTED');
273
+ $irp->Options->setShortcodeUsed(TRUE);
274
+ return;
275
+ }*/
276
+
277
+ $context=new IRP_HTMLContext();
278
+ $irp->Options->setRewriteBoxesWritten(0);
279
+ $body=$context->execute($body);
280
+ $irp->Log->pauseTime();
281
+ $irp->Log->info('TheContent: BODY SUCCESSULLY CREATED');
282
+ //$body=apply_filters('the_content', $body);
283
+ //$post->post_content=$body;
284
+ return $body;
285
+ }
286
+ function irp_ui_first_time() {
287
+ global $irp;
288
+ if($irp->Options->isShowActivationNotice()) {
289
+ //$tcmp->Options->pushSuccessMessage('FirstTimeActivation');
290
+ //$tcmp->Options->writeMessages();
291
+ $irp->Options->setShowActivationNotice(FALSE);
292
+ }
293
+ }
294
+ function irp_get_list_posts() {
295
+
296
+ global $wpdb;
297
+
298
+ $result = array();
299
+
300
+ $search = strip_tags(trim($_GET['q']));
301
+ add_filter('posts_where', function( $where ) use ($search) {
302
+ $where .= (" AND post_title LIKE '%" . $search . "%'");
303
+ return $where;
304
+ });
305
+
306
+ $query = array(
307
+ 'posts_per_page' => -1,
308
+ 'post_status' => 'publish',
309
+ 'post_type' => esc_attr($_REQUEST['irp_post_type']),
310
+ 'order' => 'ASC',
311
+ 'orderby' => 'title',
312
+ 'suppress_filters' => false,
313
+ );
314
+
315
+ $posts = get_posts( $query );
316
+
317
+ foreach ($posts as $this_post) {
318
+
319
+ $post_title = $this_post->post_title;
320
+ $id = $this_post->ID;
321
+
322
+ $result[] = array(
323
+ 'text' => $post_title,
324
+ 'id' => $id,
325
+ );
326
+
327
+ }
328
+
329
+ $posts['items'] = $result;
330
+ echo json_encode($posts);
331
+
332
+ die();
333
+
334
+ }
335
+ add_action( 'wp_ajax_irp_list_posts', 'irp_get_list_posts' );
includes/install.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ register_activation_hook(IRP_PLUGIN_FILE, 'irp_install');
3
+ function irp_install($networkwide=NULL) {
4
+ global $wpdb, $irp;
5
+
6
+ $time=$irp->Options->getPluginInstallDate();
7
+ if($time==0) {
8
+ $irp->Options->setPluginInstallDate(time());
9
+ }
10
+ $irp->Options->setPluginUpdateDate(time());
11
+ $irp->Options->setPluginFirstInstall(TRUE);
12
+ $irp->Options->setTrackingLastSend(0);
13
+ }
14
+
15
+ add_action('admin_init', 'irp_first_redirect');
16
+ function irp_first_redirect() {
17
+ global $irp;
18
+ if ($irp->Options->isPluginFirstInstall()) {
19
+ $irp->Options->setPluginFirstInstall(FALSE);
20
+ if (!$irp->Options->isPluginFirstInstall()) {
21
+ $irp->Options->setShowActivationNotice(TRUE);
22
+ $irp->Options->setShowWhatsNew(TRUE);
23
+ $irp->Utils->redirect(IRP_PAGE_SETTINGS);
24
+ }
25
+ }
26
+ }
27
+
28
+
29
+
includes/uninstall.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+ register_deactivation_hook(IRP_PLUGIN_FILE, 'irp_uninstall');
3
+ function irp_uninstall($networkwide=NULL) {
4
+ global $wpdb, $irp;
5
+ $irp->Options->setActive(FALSE);
6
+ }
7
+ ?>
index.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Inline Related Posts
4
+ Plugin URI: http://intellywp.com/intelly-related-posts/
5
+ Description: Finally the plugin to insert INLINE related posts.
6
+ Author: IntellyWP
7
+ Author URI: http://intellywp.com/
8
+ Email: support@intellywp.com
9
+ Version: 2.2.4
10
+ */
11
+ define('IRP_PLUGIN_PREFIX', 'IRP_');
12
+ define('IRP_PLUGIN_FILE',__FILE__);
13
+ define('IRP_PLUGIN_SLUG', 'intelly-related-posts');
14
+ define('IRP_PLUGIN_NAME', 'Inline Related Posts');
15
+ define('IRP_PLUGIN_VERSION', '2.2.4');
16
+ define('IRP_PLUGIN_AUTHOR', 'IntellyWP');
17
+ define('IRP_PLUGIN_ROOT', dirname(__FILE__).'/');
18
+ define('IRP_PLUGIN_IMAGES', plugins_url( 'assets/images/', __FILE__ ));
19
+ define('IRP_PLUGIN_ASSETS', plugins_url( 'assets/', __FILE__ ));
20
+
21
+ define('IRP_LOGGER', FALSE);
22
+ define('IRP_DEBUG_BLOCK', FALSE);
23
+ define('IRP_DISABLE_RELATED', FALSE);
24
+ define('IRP_QUERY_POSTS_OF_TYPE', 1);
25
+ define('IRP_QUERY_POST_TYPES', 2);
26
+ define('IRP_QUERY_CATEGORIES', 3);
27
+ define('IRP_QUERY_TAGS', 4);
28
+
29
+ define('IRP_ENGINE_SEARCH_CATEGORIES_TAGS', 0);
30
+ define('IRP_ENGINE_SEARCH_CATEGORIES', 1);
31
+ define('IRP_ENGINE_SEARCH_TAGS', 2);
32
+
33
+ define('IRP_PLUGIN_URI', plugins_url('/', __FILE__ ));
34
+ define('IRP_INTELLYWP_SITE', 'http://www.intellywp.com/');
35
+ define('IRP_INTELLYWP_ENDPOINT', IRP_INTELLYWP_SITE.'wp-content/plugins/intellywp-manager/data.php');
36
+ define('IRP_PAGE_FAQ', IRP_INTELLYWP_SITE.IRP_PLUGIN_SLUG);
37
+ define('IRP_PAGE_WORDPRESS', 'https://wordpress.org/plugins/'.IRP_PLUGIN_SLUG.'/');
38
+ define('IRP_PAGE_PREMIUM', IRP_INTELLYWP_SITE.IRP_PLUGIN_SLUG);
39
+ define('IRP_PAGE_SETTINGS', admin_url().'options-general.php?page='.IRP_PLUGIN_SLUG);
40
+
41
+ define('IRP_TAB_SETTINGS', 'settings');
42
+ define('IRP_TAB_SETTINGS_URI', IRP_PAGE_SETTINGS.'&tab='.IRP_TAB_SETTINGS);
43
+ define('IRP_TAB_ABOUT', 'about');
44
+ define('IRP_TAB_ABOUT_URI', IRP_PAGE_SETTINGS.'&tab='.IRP_TAB_ABOUT);
45
+ define('IRP_TAB_DOCS', 'docs');
46
+ define('IRP_TAB_DOCS_URI', 'http://support.intellywp.com/category/58-inline-related-posts');
47
+ define('IRP_TAB_WHATS_NEW', 'whatsnew');
48
+ define('IRP_TAB_WHATS_NEW_URI', IRP_PAGE_SETTINGS.'&tab='.IRP_TAB_WHATS_NEW);
49
+
50
+ include_once(dirname(__FILE__).'/autoload.php');
51
+ irp_include_php(dirname(__FILE__).'/includes/');
52
+
53
+ global $irp;
54
+ $irp=new IRP_Singleton();
55
+ $irp->init();
languages/Lang.txt ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 make Intelly plugins for your Intelly site
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=Inline Related Posts (v.{0})
21
+ FaqTitle=F.A.Q. Frequently Asked Question
22
+ FeedbackHeader=Are you looking for new features? Send us a feedback
23
+ AboutText1=We are Stefan and Alex, two guys in love with Wordpress, coding and marketing! Our company IntellyWP is an idea to bring Intelly ideas to your Intelly site ;)
24
+ AboutText2=Feel free to reach us by the feedback form below.
25
+
26
+ CodeDeleteNotice=Tracking code "#{0} ({1})" successfully deleted
27
+ CodeUpdateNotice=Tracking code "#{0} ({1})" successfully updated
28
+ CodeAddNotice=Tracking code "#{0} ({1})" successfully added
29
+
30
+ FreeLicenseReached=You have reached the FREE version limit. Please buy the PREMIUM version or delete unused tracking code and create new ones.
31
+ EditTitle=Edit tracking code
32
+ EditSubtitle=Edit the information that you need and click "Save"
33
+ AddTitle=New tracking code
34
+ AddSubtitle=Fill in the information and click "Save"
35
+ EnableAllowTrackingNotice1=Currently we receive plugin usage information. It allows us to have a BETTER development so many many thanks from the development team.
36
+ EnableAllowTrackingNotice2=If you want to stop tracking please click <a href="{0}">HERE :(</a>
37
+ DisableAllowTrackingNotice1=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.
38
+ DisableAllowTrackingNotice2=Please allow us to receive this information clicking <a href="{0}">HERE :)</a> once enabled you can disallow them in the About tab.
39
+ DisableAllowTrackingNotice3=Welcome on board from the IntellyWP team and many thanks for choosing our products!
40
+
41
+ Editor.active=Active?
42
+ Editor.name=Name
43
+ Editor.code=Paste your Tracking Code here
44
+ Editor.position.0=Before &lt;/HEAD&gt;
45
+ Editor.position.1=After &lt;BODY&gt;
46
+ Editor.position.2=Before &lt;/BODY&gt;
47
+ Editor.position=Position inside the code
48
+ Editor.includeEverywhereActive=Include in the whole website (pages, posts and archives)
49
+ Editor.includeCategoriesActive=Include in posts with specific categories
50
+ Editor.includeTagsActive=Include in posts with specific tags
51
+ Editor.includePostsOfTypeActive=Include in "<b>{0}</b>"
52
+ Editor.exceptCategoriesActive=Exclude in posts with specific categories
53
+ Editor.exceptTagsActive=Exclude in posts with specific tags
54
+ Editor.exceptPostsOfTypeActive=Exclude in "<b>{0}</b>"
55
+ Editor.includeLastPostsActive=Include in latest posts (specify the number of posts)
56
+
57
+ DeactivateSuccess=License key "{0}" successfully deactivated
58
+ DeactivateError=Errors deactivating key. Network problem??
59
+ ActivateSuccess1=License key "{0}" successfully activated
60
+ ActivateSuccess2=CONGRATS...YOU ARE NOW A PREMIUM MEMBER! :)
61
+ ActivateError=Errors activating key. Network problem or wrong activation key.
62
+
63
+ LicenseSection=License information
64
+ LicenseSectionSubtitle=Insert the activation key received by email in the text below to see all the settings
65
+ MetaboxSection=Metabox integration
66
+ MetaboxSectionSubtitle=You will display a metabox to disable the plugin in a specific post or page.
67
+ License.metabox=In "<b>{0}</b>"
68
+ License.key=Insert the activation key received by email
69
+ EmptyTrackingList=Your tracking code list is empty, please <a href="{0}">CLICK HERE</a> to create new ones.
70
+
71
+ Notice.ProHeader1=Do you like this plugin?
72
+ Notice.ProHeader2=Using the <b>PREMIUM</b> version you can also include/exclude tracking code:
73
+ Notice.ProFeature1=In your custom post type {0}
74
+ Notice.ProFeature2=In the latest post
75
+ Notice.ProFeature3=In specific categories
76
+ Notice.ProFeature4=In specific tags
77
+
78
+ QuestionActiveOn=Do you want to activate this code?
79
+ QuestionActiveOff=Do you want to deactivate this code?
80
+
81
+ GeneralSection=Style Settings
82
+ GeneralSectionSubtitle=Just few settings and Kaboooom!!
83
+ RewriteSection=Plugin Settings
84
+ RewriteSectionSubtitle=Set the plugin's behavior.
85
+ EngineSection=Engine Settings
86
+ EngineSectionSubtitle=Choose how the plugin discovers similar posts
87
+ PreviewSection=Real time preview
88
+ PreviewSectionSubtitle=Change any above settings to refresh preview OR <a href="javascript:IRP_changeRelatedBox()">REFRESH HERE</a>
89
+ PreviewSectionMaxTime=With these settings the plugin has ran in max {0} milliseconds with {1} different posts. Enjoy! :)
90
+ Settings.irpActive=Active?
91
+ Settings.irpText=Related text
92
+ Settings.irpBackgroundColor=Background Color
93
+ Settings.irpBorderColor=Border Color
94
+ Settings.irpRewriteActive=Insert in already existing posts?
95
+ Settings.irpRewriteBoxesCount=How many boxes per single post?
96
+ Settings.irpRewritePostsInBoxCount=Max posts per box N.
97
+ Settings.irpRewriteThreshold=Interval between the boxes <i>(minimum N° words)</i>
98
+ Settings.irpRewriteAtEnd=Insert a box at the end of the post? (if needed)
99
+ Settings.irpRewritePostType=Use on <b>{0}</b>
100
+ Settings.irpRewritePostsDays=Only posts of last N. days<br /><i>(set zero for no limits)</i>
101
+ Settings.irpEngineSearch=Search similar posts
102
+ Settings.irpEngineSearch.0=Using categories and tags
103
+ Settings.irpEngineSearch.1=Using only categories
104
+ Settings.irpEngineSearch.2=Using only tags
105
+ Settings.irpShowPoweredBy=Display "Powered by" text<br/><i>(and show us some love :)</i>
106
+ Settings.irpTemplate=Box template
107
+ Settings.irpTemplateBackgroundColor=Background color
108
+ Settings.irpTemplateBorderColor=Left border color
109
+ Settings.irpTemplateShadow=Shadow?
110
+ Settings.irpTemplateRelatedTextColor=Related Text Color
111
+ Settings.template-linkRel=Link "rel" attribute
112
+ Settings.template-linkTarget=Link "target" attribute
113
+ Settings.key=Activation key
114
+
115
+ TemplateName=Example template "{0}"
116
+ FirstTimeActivation=Thank you for activating our plugin. This is the page settings where you need to start to configure it. You will see this box only the first time.
117
+ Settings.metabox=Integrate in <b>"{0}"</b>
118
+ EditorSubtitle=Select the item that you want to insert into the box automatically created by the Intelly Related Posts
119
+ Faq.Question1=Why should I use this plugin?
120
+ Faq.Response1=Because it will increase the page views on your site, improving engagement and reducing your bounce rate.
121
+ Faq.Question2=Can I use the Inline related Posts plugin along with another Related posts plugin?
122
+ Faq.Response2=Yes you can! Our plugin puts fancy boxes INSIDE the content, not at the end of it.
123
+ Faq.Question3=Will this plugin break the structure of my content?
124
+ Faq.Response3=NOPE. Our algorithm knows HTML tags and avoid placing the boxes in the wrong place!
125
+ Faq.Question4=Will this plugin slow my website?
126
+ Faq.Response4=Absolutely Not! Inline Related Posts is built with lightweight code and you won’t notice any difference in speed using it.
127
+
128
+ EasySection=Easy Configuration
129
+ CoolSection=Cool Configuration (are you ready?)
130
+ Settings.template-ctaText=Related text or Call-To-Action
131
+ Settings.template-textTransform=Text transform
132
+ Settings.template-useDefaults=Use template colors schema
133
+ Settings.template-ctaTextColor=Related Text Color
134
+ Settings.template-ctaTextColorHover=Related Text Color Hover
135
+ Settings.template-ctaBoxColor=Related Box Color
136
+ Settings.template-ctaBoxColorHover=Related Box Color Hover
137
+ Settings.template-boxColor=Box Background Color
138
+ Settings.template-boxColorHover=Box Color Hover
139
+ Settings.template-postTitleColor=Post Title Color
140
+ Settings.template-postTitleColorHover=Post Title Color Hover
141
+ Settings.template-borderColor=Border Color
142
+ Settings.template-borderColorHover=Border Color Hover
143
+ Settings.template-useHoverDefaults=Use template hover colors schema
144
+ Settings.template-template=Theme
145
+ Settings.template-hasShadow=Display border shadow
146
+ Settings.template-hasPoweredBy=Display "Powered by" text <i>(and show us some love :)</i>
147
+ Settings.template-boxOpacity=Initial opacity %
148
+ Settings.Color.border=Border Color
149
+ Settings.Color.arrow=Arrow background Color
150
+ Settings.Color.hover=Hover Box background Color
151
+ Settings.Color.button=Button Color
152
+ Notice.DontSave=Please <a href="{0}">Buy PREMIUM</a> to use this theme
153
+
154
+ Notice.ProHeader1=Do you like this plugin?
155
+ Notice.ProHeader2=With <b>PREMIUM</b> version you can have awesome features like:
156
+ Notice.ProFeature1=Configure UNLIMITED Inline Related Boxes
157
+ Notice.ProFeature2=Premium box themes with featured images
158
+ Notice.ProFeature3=Configure hover effect with different colors
159
+ Notice.ProFeature4=24/7 World champion support
160
+ Notice.ProFeature5=FREE IntellyTrust: Solve your problem in 48h
161
+ Notice.ProFeature6=100 seconds Install & Forget
162
+ Notice.ProCTA=Check all premium features now ››
163
+
164
+ YouHaveThePremiumVersion1=You have installed the PREMIUM version of this plugin, please click <a href="{0}">here</a> to have access at all the features.
165
+ YouHaveThePremiumVersion2=You can deactivate the "<b>Inline Related Posts</b>" plugin and only still active the "<b>Inline Related Posts PRO</b>" plugin
166
+
167
+ Settings.marginTop=CSS margin-top
168
+ Settings.marginBottom=CSS margin-bottom
169
+ GuruInfo=Below some GURU info (useful to request support at support@intellywp.com)
170
+ XdebugException=XdebugException: please contact our support at support@intellywp.com. Few hours and we will help you, guaranteed :)
readme.txt ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Inline Related Posts ===
2
+ Contributors: IntellyWP
3
+ Donate link: http://intellywp.com/intelly-related-posts/
4
+ Tags: related post,related posts,inline related posts, inside related posts, suggestions, similar post, similar posts, related,contextual, relations, seo, bounce rate, internal links, similarity, related content, inline related post, Zemanta, inline, Related Links, Contextual Related Posts, YARPP recommendation engine, YARPP
5
+ Requires at least: 2.7
6
+ Tested up to: 5.2
7
+
8
+ Inline Related Posts AUTOMATICALLY inserts related posts INSIDE your content, capturing immediately the reader's attention.
9
+
10
+ == Description ==
11
+
12
+ Companies like Entrepreneur, The Wall Street Journal, BBC, Business Insider, Financial Times and many others understood this concept and embraced it as you can see in this GIF in <a href="https://wordpress.org/plugins/intelly-related-posts/screenshots/">Screenshots</a>.
13
+
14
+ In <a href="http://www.intellywp.com" target="_blank">IntellyWP</a> we take care of the marketing aspects of your Wordpress site and today we have brought to you the same technology they use, to help you to increase engagement, page views and to reduce the bounce rate.
15
+
16
+ > <strong>Just one week after testing this plugin on a low traffic site, our page views increased by 99%.</strong>
17
+
18
+ <strong>ANOTHER IMPORTANT POINT OF VIEW</strong>
19
+ <br>
20
+ How many things have you have in the footer post?
21
+
22
+ * The author box?
23
+ * Subscription to your newsletter?
24
+ * Maybe you ask users to share the post on social networks?
25
+ * You ask them to leave a comment?
26
+ * And also... to read related posts?
27
+
28
+ Do you know that asking too many things is equal to ask nothing?
29
+
30
+ [youtube https://www.youtube.com/watch?v=CjdTr14Nd1g]
31
+
32
+ Inline related posts plugin bring a new experience to your visitors and help you to win the fight of catching readers attention ;)
33
+
34
+ > With Inline Related Posts Plugin you can:<br>
35
+ > 1. Put related posts boxes INSIDE your content (<a href="https://wordpress.org/plugins/intelly-related-posts/screenshots/">see Screenshots</a>)<br>
36
+ > 2. Automatically put multiple boxes in all your posts<br>
37
+ > 3. Automatically detect line breaks (without destroy your paragraphs or headlines)<br>
38
+ > 4. Choose over 20+ combinations of style (themes, colors, hover)
39
+
40
+
41
+ <a href="https://downloads.wordpress.org/plugin/intelly-related-posts.zip">Download now the Inline Related posts plugin into your Wordpress.</a>
42
+ <br>
43
+ <br>
44
+ Brought to you by IntellyWP. Intelly solution for your Intelly site ;)
45
+
46
+ == Installation ==
47
+
48
+ 1. Download our plugin
49
+ 2. Upload to your /wp-contents/plugins/ directory.
50
+ 3. Activate the plugin through the "Plugins" menu in WordPress.
51
+ 4. You will be redirected to Settings &gt;&gt; Inline Related Posts
52
+
53
+ == Frequently Asked Questions ==
54
+
55
+ = Why should I use this plugin? =
56
+
57
+ Because it will increase the page views on your site, improving engagement and reducing your bounce rate.
58
+
59
+ = Can I use the Inline related Posts plugin along with another Related posts plugin? =
60
+
61
+ Yes you can! Our plugin puts fancy boxes INSIDE the content, not at the end of it.
62
+
63
+ = Will this plugin break the structure of my content? =
64
+
65
+ NOPE. Our algorithm knows HTML tags and avoid placing the boxes in the wrong place!
66
+
67
+ = Do you have some others fancy box styles? =
68
+
69
+ Yes! We have other cool styles and features in the PRO version. Check it out <a href="https://intellywp.com/intelly-related-posts/">https://intellywp.com/intelly-related-posts/</a>
70
+
71
+ = Will this plugin slow my website? =
72
+
73
+ Absolutely Not! Inline Related Posts is built with lightweight code so you won’t notice any difference in speed using it.
74
+
75
+ == Screenshots ==
76
+
77
+ 1. Some example of famous websites with "Related post box"
78
+ 2. An example of a style that you can use
79
+ 3. Another example of a style that you can use
80
+ 4. Another example of a style that you can use
81
+ 5. Hover effect is allowed using this theme
82
+ 6. Our Intelly Line Breaks technology which detects grammar rules and avoids content breaks.
83
+ 7. The backend of our plugin. Live preview available and super fast options to fit your theme style.
84
+ 8. A Box Theme of Inline Related Posts PRO. Check other PREMIUM feature <a href="https://intellywp.com/intelly-related-posts/">here</a>. (https://intellywp.com/intelly-related-posts/)
85
+ 9. Another Box Theme of Inline Related Posts PRO. Check other PREMIUM feature <a href="https://intellywp.com/intelly-related-posts/">here</a>. (https://intellywp.com/intelly-related-posts/)
86
+
87
+ == Changelog ==
88
+
89
+ = 2.2.4 =
90
+ *Release Date - 2019-05-18*
91
+
92
+ * Tested with WP 5.2 Plugin updated and supported.
93
+ * [Improvement] Prevent the related posts inside specific divs
94
+
95
+ = 2.2.3 =
96
+ *Release Date - 2019-03-16*
97
+
98
+ * Tested with WP 5.1.1. Plugin updated and supported.
99
+
100
+ = 2.2.2 =
101
+ *Release Date - 2019-02-21*
102
+
103
+ * [NEW] Ajax dropdown to choose a specific post for our "irp" shortcode from the editor button.
104
+ * [NEW] Ajax dropdown to choose a specific page for our "irp" shortcode from the editor button.
105
+ * Finally compatible with WP 5.0.3. Plugin updated and supported.
106
+
107
+ = 2.2.1 =
108
+ *Release Date - 2018-05-01*
109
+
110
+ * Finally compatible with WP 4.9.5. Plugin updated and supported.
111
+
112
+ = 2.2.0 =
113
+ *Release Date - 21/08/2016*
114
+
115
+ * Compatible with PHP < 5.3
116
+ * No also inline image are recognized if featured image is not defined
117
+
118
+ = 2.1.8 =
119
+ *Release Date - 27/04/2016*
120
+ * Documentation link fixed
121
+ = 2.1.7 =
122
+ *Release Date - 19/09/2015*
123
+
124
+ * [Bugfix] hasPoweredBy not is default disable due to WP repository guidelines
125
+
126
+ = 2.1.6 =
127
+ *Release Date - 13/09/2015*
128
+
129
+ * [Improvement] Improvement the "wp-caption" recognition
130
+
131
+ = 2.1.5 =
132
+ *Release Date - 12/09/2015*
133
+
134
+ * [Improvement] Improvement in "div" detection
135
+ * [Bugfix] Fixed vertical-alignment in Firefox
136
+
137
+ = 2.1.4 =
138
+ *Release Date - 11/09/2015*
139
+
140
+ * [Bugfix] Fixed bugs on "irp" shortcode
141
+
142
+ = 2.1.3 =
143
+ *Release Date - 09/09/2015*
144
+
145
+ * [Bugfix] Fixed bugs on "style" tag in content
146
+
147
+ = 2.1.2 =
148
+ *Release Date - 27/08/2015*
149
+
150
+ * [Bugfix] Fixed bugs on related box placement
151
+
152
+ = 2.1.0 =
153
+ *Release Date - 26/08/2015*
154
+
155
+ * [Improvements] Included into the WP menu only if user has manage_options rights
156
+ * [Bugfix] Fixed bugs on bottom spacing
157
+ * [Improvements] Inserted as parameters CSS margin-top and CSS margin-bottom
158
+ * [Improvements] Various fixed
159
+
160
+ = 2.0.4 =
161
+ *Release Date - 23/08/2015*
162
+
163
+ * [Improvements] Various fixed
164
+
165
+ = 2.0.3 =
166
+ *Release Date - 09/07/2015*
167
+
168
+ * [Bugfix] Speed optimization
169
+ * [Bugfix] Corrected the function to filter only recent posts
170
+ * Minor bugfix
171
+
172
+ = 2.0.2 =
173
+ *Release Date - 06/07/2015*
174
+
175
+ * Minor bugfix
176
+
177
+ = 2.0.1 =
178
+ *Release Date - 05/07/2015*
179
+
180
+ * [Bugfix] Fixed bug with PRE tag
181
+ * [Bugfix] Fixed notice Array to string conversion in ../intelly-related-posts/index.php on line 127
182
+ * [NEW] Created themes for the plugin
183
+ * [NEW] Created 2 different themes for free with various effect
184
+ * [NEW] Created 3 different themes in PRO version with various effect
185
+
186
+ = 1.3.4 =
187
+ *Release Date - 06/06/2015*
188
+
189
+ * Added rel="nofollow" by default with a dropdown where you can choose also dofollow if you prefer
190
+
191
+ = 1.3.3 =
192
+ *Release Date - 27/05/2015*
193
+
194
+ * [Thanks to msshams] Bugfix persian language
195
+ * [Thanks to reweb] Bugfix Parse error: syntax error, unexpected ':' in [...] wp-content/plugins/intelly-related-posts/index.php on line 118
196
+
197
+ = 1.3.2 =
198
+ *Release Date - 14/05/2015*
199
+
200
+ * Tested with a lot of websites, blogs, etc
201
+ * Approved by WP community
202
+
203
+ = 1.1 =
204
+ *Release Date - 09/05/2015*
205
+
206
+ * HTML parsing to insert properly Inline Related Posts automatically
207
+ * Bugfixes and test with a lots of posts
208
+
209
+ = 1.0 =
210
+ * First release
screenshot-1.gif 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.jpg ADDED
Binary file
screenshot-7.png ADDED
Binary file
screenshot-8.png ADDED
Binary file
screenshot-9.png ADDED
Binary file